changeset 135:242e33c0e383

Added dnd source, ByteArrayTransfer,Clipboard completed
author Frank Benoit <benoit@tionex.de>
date Wed, 13 Feb 2008 04:51:22 +0100
parents fa7d7d66b9ed
children 04e357b8343d
files dsss.conf dwt/dnd/ByteArrayTransfer.d dwt/dnd/Clipboard.d dwt/dnd/DND.d dwt/dnd/DNDEvent.d dwt/dnd/DNDListener.d dwt/dnd/DragSource.d dwt/dnd/DragSourceAdapter.d dwt/dnd/DragSourceEffect.d dwt/dnd/DragSourceEvent.d dwt/dnd/DragSourceListener.d dwt/dnd/DropTarget.d dwt/dnd/DropTargetAdapter.d dwt/dnd/DropTargetEffect.d dwt/dnd/DropTargetEvent.d dwt/dnd/DropTargetListener.d dwt/dnd/FileTransfer.d dwt/dnd/HTMLTransfer.d dwt/dnd/OleEnumFORMATETC.d dwt/dnd/RTFTransfer.d dwt/dnd/TableDragSourceEffect.d dwt/dnd/TableDropTargetEffect.d dwt/dnd/TextTransfer.d dwt/dnd/Transfer.d dwt/dnd/TransferData.d dwt/dnd/TreeDragSourceEffect.d dwt/dnd/TreeDropTargetEffect.d dwt/dnd/URLTransfer.d
diffstat 28 files changed, 5764 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/dsss.conf	Wed Feb 13 03:22:44 2008 +0100
+++ b/dsss.conf	Wed Feb 13 04:51:22 2008 +0100
@@ -3,6 +3,7 @@
 [dwt]
 type=library
 debugflags+=-g -gc -debug
+exclude=dwt/dnd
 
 
 [simple.d]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/ByteArrayTransfer.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.ByteArrayTransfer;
+
+import dwt.internal.ole.win32.COM;
+import dwt.internal.ole.win32.OBJIDL;
+import dwt.internal.win32.OS;
+
+import dwt.dnd.DND;
+import dwt.dnd.Transfer;
+import dwt.dnd.TransferData;
+
+import dwt.dwthelper.utils;
+
+/**
+ * The class <code>ByteArrayTransfer</code> provides a platform specific
+ * mechanism for converting a java <code>byte[]</code> to a platform
+ * specific representation of the byte array and vice versa.  See
+ * <code>Transfer</code> for additional information.
+ *
+ * <p><code>ByteArrayTransfer</code> is never used directly but is sub-classed
+ * by transfer agents that convert between data in a java format such as a
+ * <code>String</code> and a platform specific byte array.
+ *
+ * <p>If the data you are converting <b>does not</b> map to a
+ * <code>byte[]</code>, you should sub-class <code>Transfer</code> directly
+ * and do your own mapping to a platform data type.</p>
+ *
+ * <p>The following snippet shows a subclass of ByteArrayTransfer that transfers
+ * data defined by the class <code>MyType</code>.</p>
+ *
+ * <pre><code>
+ * public class MyType {
+ *  public String fileName;
+ *  public long fileLength;
+ *  public long lastModified;
+ * }
+ * </code></pre>
+ *
+ * <pre><code>
+ * public class MyTypeTransfer extends ByteArrayTransfer {
+ *
+ *  private static final String MYTYPENAME = "my_type_name";
+ *  private static final int MYTYPEID = registerType(MYTYPENAME);
+ *  private static MyTypeTransfer _instance = new MyTypeTransfer();
+ *
+ * private MyTypeTransfer() {}
+ *
+ * public static MyTypeTransfer getInstance () {
+ *  return _instance;
+ * }
+ * public void javaToNative (Object object, TransferData transferData) {
+ *  if (object is null || !(object instanceof MyType[])) return;
+ *
+ *  if (isSupportedType(transferData)) {
+ *      MyType[] myTypes = (MyType[]) object;
+ *      try {
+ *          // write data to a byte array and then ask super to convert to pMedium
+ *          ByteArrayOutputStream out = new ByteArrayOutputStream();
+ *          DataOutputStream writeOut = new DataOutputStream(out);
+ *          for (int i = 0, length = myTypes.length; i &lt; length;  i++){
+ *              byte[] buffer = myTypes[i].fileName.getBytes();
+ *              writeOut.writeInt(buffer.length);
+ *              writeOut.write(buffer);
+ *              writeOut.writeLong(myTypes[i].fileLength);
+ *              writeOut.writeLong(myTypes[i].lastModified);
+ *          }
+ *          byte[] buffer = out.toByteArray();
+ *          writeOut.close();
+ *
+ *          super.javaToNative(buffer, transferData);
+ *
+ *      } catch (IOException e) {
+ *      }
+ *  }
+ * }
+ * public Object nativeToJava(TransferData transferData){
+ *
+ *  if (isSupportedType(transferData)) {
+ *
+ *      byte[] buffer = (byte[])super.nativeToJava(transferData);
+ *      if (buffer is null) return null;
+ *
+ *      MyType[] myData = new MyType[0];
+ *      try {
+ *          ByteArrayInputStream in = new ByteArrayInputStream(buffer);
+ *          DataInputStream readIn = new DataInputStream(in);
+ *          while(readIn.available() > 20) {
+ *              MyType datum = new MyType();
+ *              int size = readIn.readInt();
+ *              byte[] name = new byte[size];
+ *              readIn.read(name);
+ *              datum.fileName = new String(name);
+ *              datum.fileLength = readIn.readLong();
+ *              datum.lastModified = readIn.readLong();
+ *              MyType[] newMyData = new MyType[myData.length + 1];
+ *              System.arraycopy(myData, 0, newMyData, 0, myData.length);
+ *              newMyData[myData.length] = datum;
+ *              myData = newMyData;
+ *          }
+ *          readIn.close();
+ *      } catch (IOException ex) {
+ *          return null;
+ *      }
+ *      return myData;
+ *  }
+ *
+ *  return null;
+ * }
+ * protected String[] getTypeNames(){
+ *  return new String[]{MYTYPENAME};
+ * }
+ * protected int[] getTypeIds(){
+ *  return new int[] {MYTYPEID};
+ * }
+ * }
+ * </code></pre>
+ */
+public abstract class ByteArrayTransfer : Transfer {
+
+public TransferData[] getSupportedTypes() {
+    int[] types = getTypeIds();
+    TransferData[] data = new TransferData[types.length];
+    for (int i = 0; i < types.length; i++) {
+        data[i] = new TransferData();
+        data[i].type = types[i];
+        data[i].formatetc = new FORMATETC();
+        data[i].formatetc.cfFormat = types[i];
+        data[i].formatetc.dwAspect = COM.DVASPECT_CONTENT;
+        data[i].formatetc.lindex = -1;
+        data[i].formatetc.tymed = COM.TYMED_HGLOBAL;
+    }
+    return data;
+}
+
+public bool isSupportedType(TransferData transferData){
+    if (transferData is null) return false;
+    int[] types = getTypeIds();
+    for (int i = 0; i < types.length; i++) {
+        FORMATETC* format = transferData.formatetc;
+        if (format.cfFormat is types[i] &&
+            (format.dwAspect & COM.DVASPECT_CONTENT) is COM.DVASPECT_CONTENT &&
+            (format.tymed & COM.TYMED_HGLOBAL) is COM.TYMED_HGLOBAL  )
+            return true;
+    }
+    return false;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts a java
+ * <code>byte[]</code> to a platform specific representation.  For additional
+ * information see <code>Transfer#javaToNative</code>.
+ *
+ * @see Transfer#javaToNative
+ *
+ * @param object a java <code>byte[]</code> containing the data 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
+ */
+protected void javaToNative (Object object, TransferData transferData) {
+    if (!checkByteArray(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    // 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.
+    byte[] data = (cast(ArrayWrapperByte)object).array;
+    int size = data.length;
+    auto newPtr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, size);
+    OS.MoveMemory(newPtr, data.ptr, size);
+    transferData.stgmedium = new STGMEDIUM();
+    transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+    transferData.stgmedium.unionField = newPtr;
+    transferData.stgmedium.pUnkForRelease = null;
+    transferData.result = COM.S_OK;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of a byte array to a java <code>byte[]</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @see Transfer#nativeToJava
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>byte[]</code> containing the converted data if the
+ * conversion was successful; otherwise null
+ */
+protected Object nativeToJava(TransferData transferData) {
+    if (!isSupportedType(transferData) || transferData.pIDataObject is null)  return null;
+
+    IDataObject data = transferData.pIDataObject;
+    data.AddRef();
+    FORMATETC* formatetc = transferData.formatetc;
+    STGMEDIUM* stgmedium = new STGMEDIUM();
+    stgmedium.tymed = COM.TYMED_HGLOBAL;
+    transferData.result = data.GetData(formatetc, stgmedium);
+    data.Release();
+    if (transferData.result !is COM.S_OK) return null;
+    auto hMem = stgmedium.unionField;
+    int size = OS.GlobalSize(hMem);
+    byte[] buffer = new byte[size];
+    auto ptr = OS.GlobalLock(hMem);
+    OS.MoveMemory(buffer.ptr, ptr, size);
+    OS.GlobalUnlock(hMem);
+    OS.GlobalFree(hMem);
+    return new ArrayWrapperByte(buffer);
+}
+
+bool checkByteArray(Object object) {
+    return (object !is null && ( null !is cast(ArrayWrapperByte)object) && (cast(ArrayWrapperByte)object).array.length > 0);
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/Clipboard.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,814 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.Clipboard;
+
+
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.DWTException;
+import dwt.internal.ole.win32.COM;
+import dwt.internal.ole.win32.OBJIDL;
+import dwt.internal.ole.win32.extras;
+import dwt.internal.win32.OS;
+import dwt.widgets.Display;
+
+import dwt.dnd.Transfer;
+import dwt.dnd.TransferData;
+import dwt.dnd.OleEnumFORMATETC;
+import dwt.dnd.DND;
+
+import dwt.dwthelper.utils;
+import tango.core.Thread;
+
+/**
+ * The <code>Clipboard</code> provides a mechanism for transferring data from one
+ * application to another or within an application.
+ *
+ * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
+ */
+public class Clipboard {
+
+    private Display display;
+
+    // ole interfaces
+    private _IDataObjectImpl iDataObject;
+    private int refCount;
+    private Transfer[] transferAgents;
+    private Object[] data;
+    private int CFSTR_PREFERREDDROPEFFECT;
+
+/**
+ * Constructs a new instance of this class.  Creating an instance of a Clipboard
+ * may cause system resources to be allocated depending on the platform.  It is therefore
+ * mandatory that the Clipboard instance be disposed when no longer required.
+ *
+ * @param display the display on which to allocate the clipboard
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ *
+ * @see Clipboard#dispose
+ * @see Clipboard#checkSubclass
+ */
+public this(Display display) {
+    checkSubclass ();
+    if (display is null) {
+        display = Display.getCurrent();
+        if (display is null) {
+            display = Display.getDefault();
+        }
+    }
+    if (display.getThread() !is Thread.getThis()) {
+        DND.error(DWT.ERROR_THREAD_INVALID_ACCESS);
+    }
+    this.display = display;
+    TCHAR* chFormatName = StrToTCHARz(0, "Preferred DropEffect"); //$NON-NLS-1$
+    CFSTR_PREFERREDDROPEFFECT = OS.RegisterClipboardFormat(chFormatName);
+    createCOMInterfaces();
+    this.AddRef();
+}
+
+/**
+ * Checks that this class can be subclassed.
+ * <p>
+ * The DWT class library is intended to be subclassed
+ * only at specific, controlled points. This method enforces this
+ * rule unless it is overridden.
+ * </p><p>
+ * <em>IMPORTANT:</em> By providing an implementation of this
+ * method that allows a subclass of a class which does not
+ * normally allow subclassing to be created, the implementer
+ * agrees to be fully responsible for the fact that any such
+ * subclass will likely fail between DWT releases and will be
+ * strongly platform specific. No support is provided for
+ * user-written classes which are implemented in this fashion.
+ * </p><p>
+ * The ability to subclass outside of the allowed DWT classes
+ * is intended purely to enable those not on the DWT development
+ * team to implement patches in order to get around specific
+ * limitations in advance of when those limitations can be
+ * addressed by the team. Subclassing should not be attempted
+ * without an intimate and detailed understanding of the hierarchy.
+ * </p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ */
+protected void checkSubclass () {
+    char[] name = this.classinfo.name;
+    char[] validName = Clipboard.classinfo.name;
+    if (validName!=/*eq*/name) {
+        DND.error (DWT.ERROR_INVALID_SUBCLASS);
+    }
+}
+
+/**
+ * Throws an <code>DWTException</code> if the receiver can not
+ * be accessed by the caller. This may include both checks on
+ * the state of the receiver and more generally on the entire
+ * execution context. This method <em>should</em> be called by
+ * widget implementors to enforce the standard DWT invariants.
+ * <p>
+ * Currently, it is an error to invoke any method (other than
+ * <code>isDisposed()</code>) on a widget that has had its
+ * <code>dispose()</code> method called. It is also an error
+ * to call widget methods from any thread that is different
+ * from the thread that created the widget.
+ * </p><p>
+ * In future releases of DWT, there may be more or fewer error
+ * checks and exceptions may be thrown for different reasons.
+ * </p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+protected void checkWidget () {
+    Display display = this.display;
+    if (display is null) DND.error (DWT.ERROR_WIDGET_DISPOSED);
+    if (display.getThread() !is Thread.getThis ()) DND.error (DWT.ERROR_THREAD_INVALID_ACCESS);
+    if (display.isDisposed()) DND.error(DWT.ERROR_WIDGET_DISPOSED);
+}
+
+/**
+ * If this clipboard is currently the owner of the data on the system clipboard,
+ * clear the contents.  If this clipboard is not the owner, then nothing is done.
+ * Note that there are clipboard assistant applications that take ownership of
+ * data or make copies of data when it is placed on the clipboard.  In these
+ * cases, it may not be possible to clear the clipboard.
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void clearContents() {
+    clearContents(DND.CLIPBOARD);
+}
+
+/**
+ * If this clipboard is currently the owner of the data on the specified
+ * clipboard, clear the contents.  If this clipboard is not the owner, then
+ * nothing is done.
+ *
+ * <p>Note that there are clipboard assistant applications that take ownership
+ * of data or make copies of data when it is placed on the clipboard.  In these
+ * cases, it may not be possible to clear the clipboard.</p>
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * @param clipboards to be cleared
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public void clearContents(int clipboards) {
+    checkWidget();
+    if ((clipboards & DND.CLIPBOARD) !is 0) {
+        /* OleIsCurrentClipboard([in] pDataObject)
+         * The argument pDataObject is owned by the caller so reference count does not
+         * need to be incremented.
+         */
+        if (COM.OleIsCurrentClipboard(this.iDataObject) is COM.S_OK) {
+            /* OleSetClipboard([in] pDataObject)
+             * The argument pDataObject is owned by the caller so reference count does not
+             * need to be incremented.
+             */
+            COM.OleSetClipboard(null);
+        }
+    }
+}
+
+/**
+ * Disposes of the operating system resources associated with the clipboard.
+ * The data will still be available on the system clipboard after the dispose
+ * method is called.
+ *
+ * <p>NOTE: On some platforms the data will not be available once the application
+ * has exited or the display has been disposed.</p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ */
+public void dispose () {
+    if (isDisposed()) return;
+    if (display.getThread() !is Thread.getThis ()) DND.error(DWT.ERROR_THREAD_INVALID_ACCESS);
+    /* OleIsCurrentClipboard([in] pDataObject)
+     * The argument pDataObject is owned by the caller so reference count does not
+     * need to be incremented.
+     */
+    if (COM.OleIsCurrentClipboard(this.iDataObject) is COM.S_OK) {
+        COM.OleFlushClipboard();
+    }
+    this.Release();
+    display = null;
+}
+
+/**
+ * Retrieve the data of the specified type currently available on the system
+ * clipboard.  Refer to the specific subclass of <code>Transfer</code> to
+ * determine the type of object returned.
+ *
+ * <p>The following snippet shows text and RTF text being retrieved from the
+ * clipboard:</p>
+ *
+ *    <code><pre>
+ *    Clipboard clipboard = new Clipboard(display);
+ *    TextTransfer textTransfer = TextTransfer.getInstance();
+ *    String textData = (String)clipboard.getContents(textTransfer);
+ *    if (textData !is null) System.out.println("Text is "+textData);
+ *    RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ *    String rtfData = (String)clipboard.getContents(rtfTransfer);
+ *    if (rtfData !is null) System.out.println("RTF Text is "+rtfData);
+ *    clipboard.dispose();
+ *    </code></pre>
+ *
+ * @param transfer the transfer agent for the type of data being requested
+ * @return the data obtained from the clipboard or null if no data of this type is available
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
+ * </ul>
+ *
+ * @see Transfer
+ */
+public Object getContents(Transfer transfer) {
+    return getContents(transfer, DND.CLIPBOARD);
+}
+/**
+ * Retrieve the data of the specified type currently available on the specified
+ * clipboard.  Refer to the specific subclass of <code>Transfer</code> to
+ * determine the type of object returned.
+ *
+ * <p>The following snippet shows text and RTF text being retrieved from the
+ * clipboard:</p>
+ *
+ *    <code><pre>
+ *    Clipboard clipboard = new Clipboard(display);
+ *    TextTransfer textTransfer = TextTransfer.getInstance();
+ *    String textData = (String)clipboard.getContents(textTransfer);
+ *    if (textData !is null) System.out.println("Text is "+textData);
+ *    RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ *    String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD);
+ *    if (rtfData !is null) System.out.println("RTF Text is "+rtfData);
+ *    clipboard.dispose();
+ *    </code></pre>
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * @param transfer the transfer agent for the type of data being requested
+ * @param clipboards on which to look for data
+ *
+ * @return the data obtained from the clipboard or null if no data of this type is available
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
+ * </ul>
+ *
+ * @see Transfer
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public Object getContents(Transfer transfer, int clipboards) {
+    checkWidget();
+    if (transfer is null) DND.error(DWT.ERROR_NULL_ARGUMENT);
+    if ((clipboards & DND.CLIPBOARD) is 0) return null;
+    /*
+    * Bug in Windows. When a new application takes control
+    * of the clipboard, other applications may open the
+    * clipboard to determine if they want to record the
+    * clipboard updates.  When this happens, the clipboard
+    * can not be accessed until the other application is
+    * finished.  To allow the other applications to release
+    * the clipboard, use PeekMessage() to enable cross thread
+    * message sends.
+    */
+    IDataObject dataObject;
+    int retryCount = 0;
+    /* OleGetClipboard([out] ppDataObject).
+     * AddRef has already been called on ppDataObject by the callee and must be released by the caller.
+     */
+    int result = COM.OleGetClipboard(&dataObject);
+    while (result !is COM.S_OK && retryCount++ < 10) {
+        try {Thread.sleep(0.050);} catch (Exception t) {}
+        MSG msg;
+        OS.PeekMessage(&msg, null, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD);
+        result = COM.OleGetClipboard(&dataObject);
+    }
+    if (result !is COM.S_OK) return null;
+    try {
+        TransferData[] allowed = transfer.getSupportedTypes();
+        for (int i = 0; i < allowed.length; i++) {
+            if (dataObject.QueryGetData(allowed[i].formatetc) is COM.S_OK) {
+                TransferData data = allowed[i];
+                data.pIDataObject = dataObject;
+                return transfer.nativeToJava(data);
+            }
+        }
+    } finally {
+        dataObject.Release();
+    }
+    return null; // No data available for this transfer
+}
+/**
+ * Returns <code>true</code> if the clipboard has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the clipboard.
+ * When a clipboard has been disposed, it is an error to
+ * invoke any other method using the clipboard.
+ * </p>
+ *
+ * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise
+ *
+ * @since 3.0
+ */
+public bool isDisposed () {
+    return (display is null);
+}
+
+/**
+ * Place data of the specified type on the system clipboard.  More than one type
+ * of data can be placed on the system clipboard at the same time.  Setting the
+ * data clears any previous data from the system clipboard, regardless of type.
+ *
+ * <p>NOTE: On some platforms, the data is immediately copied to the system
+ * clipboard but on other platforms it is provided upon request.  As a result,
+ * if the application modifies the data object it has set on the clipboard, that
+ * modification may or may not be available when the data is subsequently
+ * requested.</p>
+ *
+ * <p>The following snippet shows text and RTF text being set on the copy/paste
+ * clipboard:
+ * </p>
+ *
+ * <code><pre>
+ *  Clipboard clipboard = new Clipboard(display);
+ *  String textData = "Hello World";
+ *  String rtfData = "{\\rtf1\\b\\i Hello World}";
+ *  TextTransfer textTransfer = TextTransfer.getInstance();
+ *  RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ *  Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
+ *  Object[] data = new Object[]{textData, rtfData};
+ *  clipboard.setContents(data, transfers);
+ *  clipboard.dispose();
+ * </code></pre>
+ *
+ * @param data the data to be set in the clipboard
+ * @param dataTypes the transfer agents that will convert the data to its
+ * platform specific format; each entry in the data array must have a
+ * corresponding dataType
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
+ *          or the length of data is not the same as the length of dataTypes</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *  @exception DWTError <ul>
+ *    <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an DWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ */
+public void setContents(Object[] data, Transfer[] dataTypes) {
+    setContents(data, dataTypes, DND.CLIPBOARD);
+}
+
+/**
+ * Place data of the specified type on the specified clipboard.  More than one
+ * type of data can be placed on the specified clipboard at the same time.
+ * Setting the data clears any previous data from the specified
+ * clipboard, regardless of type.
+ *
+ * <p>NOTE: On some platforms, the data is immediately copied to the specified
+ * clipboard but on other platforms it is provided upon request.  As a result,
+ * if the application modifies the data object it has set on the clipboard, that
+ * modification may or may not be available when the data is subsequently
+ * requested.</p>
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * <p>The following snippet shows text and RTF text being set on the copy/paste
+ * clipboard:
+ * </p>
+ *
+ * <code><pre>
+ *  Clipboard clipboard = new Clipboard(display);
+ *  String textData = "Hello World";
+ *  String rtfData = "{\\rtf1\\b\\i Hello World}";
+ *  TextTransfer textTransfer = TextTransfer.getInstance();
+ *  RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ *  Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
+ *  Object[] data = new Object[]{textData, rtfData};
+ *  clipboard.setContents(data, transfers, DND.CLIPBOARD);
+ *  clipboard.dispose();
+ * </code></pre>
+ *
+ * @param data the data to be set in the clipboard
+ * @param dataTypes the transfer agents that will convert the data to its
+ * platform specific format; each entry in the data array must have a
+ * corresponding dataType
+ * @param clipboards on which to set the data
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
+ *          or the length of data is not the same as the length of dataTypes</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *  @exception DWTError <ul>
+ *    <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an DWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ *
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public void setContents(Object[] data, Transfer[] dataTypes, int clipboards) {
+    checkWidget();
+    if (data is null || dataTypes is null || data.length !is dataTypes.length || data.length is 0) {
+        DND.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    for (int i = 0; i < data.length; i++) {
+        if (data[i] is null || dataTypes[i] is null || !dataTypes[i].validate(data[i])) {
+            DND.error(DWT.ERROR_INVALID_ARGUMENT);
+        }
+    }
+    if ((clipboards & DND.CLIPBOARD) is 0) return;
+    this.data = data;
+    this.transferAgents = dataTypes;
+    /* OleSetClipboard([in] pDataObject)
+     * The argument pDataObject is owned by the caller so the reference count does not
+     * need to be incremented.
+     */
+    int result = COM.OleSetClipboard(iDataObject);
+
+    /*
+    * Bug in Windows. When a new application takes control
+    * of the clipboard, other applications may open the
+    * clipboard to determine if they want to record the
+    * clipboard updates.  When this happens, the clipboard
+    * can not be flushed until the other application is
+    * finished.  To allow other applications to get the
+    * data, use PeekMessage() to enable cross thread
+    * message sends.
+    */
+    int retryCount = 0;
+    while (result !is COM.S_OK && retryCount++ < 10) {
+        try {Thread.sleep(0.050);} catch (Exception t) {}
+        MSG msg;
+        OS.PeekMessage(&msg, null, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD);
+        result = COM.OleSetClipboard(iDataObject);
+    }
+    if (result !is COM.S_OK) {
+        DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
+    }
+}
+private int AddRef() {
+    refCount++;
+    return refCount;
+}
+private void createCOMInterfaces() {
+    // register each of the interfaces that this object implements
+    iDataObject = new _IDataObjectImpl( this );
+}
+private void disposeCOMInterfaces() {
+    iDataObject = null;
+}
+/*
+ * EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
+ * Ownership of ppenumFormatetc transfers from callee to caller so reference count on ppenumFormatetc
+ * must be incremented before returning.  Caller is responsible for releasing ppenumFormatetc.
+ */
+LRESULT EnumFormatEtc(int dwDirection, IEnumFORMATETC* ppenumFormatetc) {
+    // only allow getting of data - SetData is not currently supported
+    if (dwDirection is COM.DATADIR_SET) return COM.E_NOTIMPL;
+    // what types have been registered?
+    TransferData[] allowedDataTypes = new TransferData[0];
+    for (int i = 0; i < transferAgents.length; i++){
+        TransferData[] formats = transferAgents[i].getSupportedTypes();
+        TransferData[] newAllowedDataTypes = new TransferData[allowedDataTypes.length + formats.length];
+        System.arraycopy(allowedDataTypes, 0, newAllowedDataTypes, 0, allowedDataTypes.length);
+        System.arraycopy(formats, 0, newAllowedDataTypes, allowedDataTypes.length, formats.length);
+        allowedDataTypes = newAllowedDataTypes;
+    }
+    OleEnumFORMATETC enumFORMATETC = new OleEnumFORMATETC();
+    enumFORMATETC.AddRef();
+    FORMATETC*[] formats = new FORMATETC*[allowedDataTypes.length + 1];
+    for (int i = 0; i < allowedDataTypes.length; i++){
+        formats[i] = allowedDataTypes[i].formatetc;
+    }
+    // include the drop effect format to specify a copy operation
+    FORMATETC* dropeffect = new FORMATETC();
+    dropeffect.cfFormat = CFSTR_PREFERREDDROPEFFECT;
+    dropeffect.dwAspect = COM.DVASPECT_CONTENT;
+    dropeffect.lindex = -1;
+    dropeffect.tymed = COM.TYMED_HGLOBAL;
+    formats[formats.length -1] = dropeffect;
+    enumFORMATETC.setFormats(formats);
+
+    // TODO: <shawn liu> do we need AddRef() here
+    *ppenumFormatetc = enumFORMATETC.getAddress();
+    return COM.S_OK;
+}
+
+private IDataObject getAddress(){
+    return iDataObject;
+}
+
+LRESULT GetData(FORMATETC *pFormatetc, STGMEDIUM *pmedium) {
+    /* Called by a data consumer to obtain data from a source data object.
+       The GetData method renders the data described in the specified FORMATETC
+       structure and transfers it through the specified STGMEDIUM structure.
+       The caller then assumes responsibility for releasing the STGMEDIUM structure.
+    */
+    if (pFormatetc is null || pmedium is null) return COM.E_INVALIDARG;
+    if (QueryGetData(pFormatetc) !is COM.S_OK) return COM.DV_E_FORMATETC;
+
+    TransferData transferData = new TransferData();
+    transferData.formatetc = new FORMATETC();
+    COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
+    transferData.type = transferData.formatetc.cfFormat;
+    transferData.stgmedium = new STGMEDIUM();
+    transferData.result = COM.E_FAIL;
+
+    if (transferData.type is CFSTR_PREFERREDDROPEFFECT) {
+        // specify that a copy operation is to be performed
+        STGMEDIUM* stgmedium = new STGMEDIUM();
+        stgmedium.tymed = COM.TYMED_HGLOBAL;
+        stgmedium.unionField = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, 4);
+        stgmedium.unionField = cast(void*)COM.DROPEFFECT_COPY;
+        stgmedium.pUnkForRelease = null;
+        COM.MoveMemory(pmedium, stgmedium, STGMEDIUM.sizeof);
+        return COM.S_OK;
+    }
+
+    // get matching transfer agent to perform conversion
+    int transferIndex = -1;
+    for (int i = 0; i < transferAgents.length; i++){
+        if (transferAgents[i].isSupportedType(transferData)){
+            transferIndex = i;
+            break;
+        }
+    }
+    if (transferIndex is -1) return COM.DV_E_FORMATETC;
+    transferAgents[transferIndex].javaToNative(data[transferIndex], transferData);
+    COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof);
+    return transferData.result;
+}
+
+LRESULT QueryGetData(FORMATETC * pFormatetc) {
+    if (transferAgents is null) return COM.E_FAIL;
+    TransferData transferData = new TransferData();
+    transferData.formatetc = new FORMATETC();
+    COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
+    transferData.type = transferData.formatetc.cfFormat;
+    if (transferData.type is CFSTR_PREFERREDDROPEFFECT) return COM.S_OK;
+    // is this type supported by the transfer agent?
+    for (int i = 0; i < transferAgents.length; i++){
+        if (transferAgents[i].isSupportedType(transferData))
+            return COM.S_OK;
+    }
+
+    return COM.DV_E_FORMATETC;
+}
+/* QueryInterface([in] iid, [out] ppvObject)
+ * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
+ * must be incremented before returning.  Caller is responsible for releasing ppvObject.
+ */
+HRESULT QueryInterface(GUID* riid, void ** ppvObject) {
+    if (riid is null || ppvObject is null) return COM.E_INVALIDARG;
+    if (COM.IsEqualGUID(riid, &COM.IIDIUnknown) || COM.IsEqualGUID(riid, &COM.IIDIDataObject) ) {
+        *ppvObject = cast(void*)cast(IUnknown)iDataObject;
+        AddRef();
+        return COM.S_OK;
+    }
+    *ppvObject = null;
+    return COM.E_NOINTERFACE;
+}
+private ULONG Release() {
+    refCount--;
+    if (refCount is 0) {
+        this.data = null;
+        this.transferAgents = null;
+        disposeCOMInterfaces();
+        COM.CoFreeUnusedLibraries();
+    }
+    return refCount;
+}
+
+/**
+ * Returns an array of the data types currently available on the system
+ * clipboard. Use with Transfer.isSupportedType.
+ *
+ * @return array of data types currently available on the system clipboard
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see Transfer#isSupportedType
+ *
+ * @since 3.0
+ */
+public TransferData[] getAvailableTypes() {
+    return getAvailableTypes(DND.CLIPBOARD);
+}
+
+/**
+ * Returns an array of the data types currently available on the specified
+ * clipboard. Use with Transfer.isSupportedType.
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * @param clipboards from which to get the data types
+ * @return array of data types currently available on the specified clipboard
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see Transfer#isSupportedType
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public TransferData[] getAvailableTypes(int clipboards) {
+    checkWidget();
+    if ((clipboards & DND.CLIPBOARD) is 0) return null;
+    FORMATETC*[] types = _getAvailableTypes();
+    TransferData[] data = new TransferData[types.length];
+    for (int i = 0; i < types.length; i++) {
+        data[i] = new TransferData();
+        data[i].type = types[i].cfFormat;
+        data[i].formatetc = types[i];
+    }
+    return data;
+}
+
+/**
+ * Returns a platform specific list of the data types currently available on the
+ * system clipboard.
+ *
+ * <p>Note: <code>getAvailableTypeNames</code> is a utility for writing a Transfer
+ * sub-class.  It should NOT be used within an application because it provides
+ * platform specific information.</p>
+ *
+ * @return a platform specific list of the data types currently available on the
+ * system clipboard
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public char[][] getAvailableTypeNames() {
+    checkWidget();
+    FORMATETC*[] types = _getAvailableTypes();
+    char[][] names = new char[][](types.length);
+    int maxSize = 128;
+    for (int i = 0; i < types.length; i++){
+        TCHAR[] buffer = NewTCHARs(0, maxSize);
+        int size = OS.GetClipboardFormatName(types[i].cfFormat, buffer.ptr, maxSize);
+        if (size !is 0) {
+            names[i] = TCHARzToStr(buffer.ptr)[0..size];
+        } else {
+            switch (types[i].cfFormat) {
+                case COM.CF_HDROP: names[i] = "CF_HDROP"; break; //$NON-NLS-1$
+                case COM.CF_TEXT: names[i] = "CF_TEXT"; break; //$NON-NLS-1$
+                case COM.CF_BITMAP: names[i] = "CF_BITMAP"; break; //$NON-NLS-1$
+                case COM.CF_METAFILEPICT: names[i] = "CF_METAFILEPICT"; break; //$NON-NLS-1$
+                case COM.CF_SYLK: names[i] = "CF_SYLK"; break; //$NON-NLS-1$
+                case COM.CF_DIF: names[i] = "CF_DIF"; break; //$NON-NLS-1$
+                case COM.CF_TIFF: names[i] = "CF_TIFF"; break; //$NON-NLS-1$
+                case COM.CF_OEMTEXT: names[i] = "CF_OEMTEXT"; break; //$NON-NLS-1$
+                case COM.CF_DIB: names[i] = "CF_DIB"; break; //$NON-NLS-1$
+                case COM.CF_PALETTE: names[i] = "CF_PALETTE"; break; //$NON-NLS-1$
+                case COM.CF_PENDATA: names[i] = "CF_PENDATA"; break; //$NON-NLS-1$
+                case COM.CF_RIFF: names[i] = "CF_RIFF"; break; //$NON-NLS-1$
+                case COM.CF_WAVE: names[i] = "CF_WAVE"; break; //$NON-NLS-1$
+                case COM.CF_UNICODETEXT: names[i] = "CF_UNICODETEXT"; break; //$NON-NLS-1$
+                case COM.CF_ENHMETAFILE: names[i] = "CF_ENHMETAFILE"; break; //$NON-NLS-1$
+                case COM.CF_LOCALE: names[i] = "CF_LOCALE"; break; //$NON-NLS-1$
+                case COM.CF_MAX: names[i] = "CF_MAX"; break; //$NON-NLS-1$
+                default: names[i] = "UNKNOWN"; //$NON-NLS-1$
+            }
+        }
+    }
+    return names;
+}
+
+private FORMATETC*[] _getAvailableTypes() {
+    FORMATETC*[] types = null;
+    IDataObject dataObject;
+    /* OleGetClipboard([out] ppDataObject).
+     * AddRef has already been called on ppDataObject by the callee and must be released by the caller.
+     */
+    if (COM.OleGetClipboard(&dataObject) !is COM.S_OK) return types;
+    IEnumFORMATETC enumFormatetc;
+    /* EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
+     * AddRef has already been called on ppenumFormatetc by the callee and must be released by the caller.
+     */
+    int rc = dataObject.EnumFormatEtc(COM.DATADIR_GET, &enumFormatetc);
+    dataObject.Release();
+    if (rc !is COM.S_OK)return types;
+    // Loop over enumerator and save any types that match what we are looking for
+    //auto rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof);
+    uint[1] pceltFetched;
+    FORMATETC rgelt;
+    enumFormatetc.Reset();
+    while (enumFormatetc.Next(1, &rgelt, pceltFetched.ptr) is COM.S_OK && pceltFetched[0] is 1) {
+        FORMATETC* formatetc = new FORMATETC();
+        COM.MoveMemory(formatetc, &rgelt, FORMATETC.sizeof);
+        FORMATETC*[] newTypes = new FORMATETC*[types.length + 1];
+        SimpleType!(FORMATETC*).arraycopy(types, 0, newTypes, 0, types.length);
+        newTypes[types.length] = formatetc;
+        types = newTypes;
+    }
+    //OS.GlobalFree(rgelt);
+    enumFormatetc.Release();
+    return types;
+}
+}
+
+private class _IDataObjectImpl : IDataObject {
+
+    Clipboard   parent;
+    this(Clipboard  p) { parent = p; }
+extern (Windows):
+    // interface of IUnknown
+    HRESULT QueryInterface(GUID* riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
+    ULONG AddRef()  { return parent.AddRef(); }
+    ULONG Release() { return parent.Release(); }
+
+    // interface IDataObject
+    LRESULT GetData( FORMATETC *pFormatetc, STGMEDIUM *pmedium) { return parent.GetData(pFormatetc, pmedium); }
+    LRESULT GetDataHere(FORMATETC * pFormatetc, STGMEDIUM * pmedium) { return COM.E_NOTIMPL; }
+    LRESULT QueryGetData(FORMATETC* pFormatetc) { return parent.QueryGetData(pFormatetc); }
+    LRESULT GetCanonicalFormatEtc(FORMATETC* pFormatetcIn, FORMATETC* pFormatetcOut) { return COM.E_NOTIMPL; }
+    LRESULT SetData(FORMATETC* pFormatetc, STGMEDIUM * pmedium, BOOL fRelease) { return COM.E_NOTIMPL; }
+    LRESULT EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC * ppenumFormatetc) { return parent.EnumFormatEtc(dwDirection, ppenumFormatetc); }
+    LRESULT DAdvise(FORMATETC* pFormatetc, DWORD advf, IAdviseSink pAdvSink, DWORD* pdwConnection) { return COM.E_NOTIMPL; }
+    LRESULT DUnadvise(DWORD dwConnection) { return COM.E_NOTIMPL; }
+    LRESULT EnumDAdvise(IEnumSTATDATA * ppenumAdvise) { return COM.E_NOTIMPL; }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DND.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,272 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DND;
+
+
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.DWTException;
+
+import tango.util.Convert;
+
+/**
+ *
+ * Class DND contains all the constants used in defining a
+ * DragSource or a DropTarget.
+ *
+ */
+public class DND {
+
+    /**
+     * The transfer mechanism for data that is being cut
+     * and then pasted or copied and then pasted (value is 1).
+     *
+     * @see Clipboard
+     *
+     * @since 3.1
+     */
+    public const static int CLIPBOARD = 1 << 0;
+
+    /**
+     * The transfer mechanism for clients that use the selection
+     * mechanism (value is 2).
+     *
+     * @see Clipboard
+     *
+     * @since 3.1
+     */
+    public const static int SELECTION_CLIPBOARD = 1 << 1;
+
+    /**
+     * Drag and Drop Operation: no drag/drop operation performed
+     * (value is 0).
+     */
+    public const static int DROP_NONE = 0;
+
+    /**
+     * Drag and Drop Operation: a copy of the data in the drag source is
+     * added to the drop target (value is 1 &lt;&lt; 0).
+     */
+    public const static int DROP_COPY = 1 << 0;
+
+    /**
+     * Drag and Drop Operation: a copy of the data is added to the drop target and
+     * the original data is removed from the drag source (value is 1 &lt;&lt; 1).
+     */
+    public const static int DROP_MOVE = 1 << 1;
+
+    /**
+     * Drag and Drop Operation: the drop target makes a link to the data in
+     * the drag source (value is 1 &lt;&lt; 2).
+     */
+    public const static int DROP_LINK = 1 << 2;
+
+    /**
+     * Drag and Drop Operation: the drop target moves the data and the drag source removes
+     * any references to the data and updates its display.  This is not available on all platforms
+     * and is only used when a non-DWT application is the drop target.  In this case, the DWT
+     * drag source is informed in the dragFinished event that the drop target has moved the data.
+     * (value is 1 &lt;&lt; 3).
+     *
+     * @see DragSourceListener#dragFinished
+     */
+    public const static int DROP_TARGET_MOVE = 1 << 3;
+
+    /**
+     * Drag and Drop Operation: During a dragEnter event or a dragOperationChanged, if no modifier keys
+     * are pressed, the operation is set to DROP_DEFAULT.  The application can choose what the default
+     * operation should be by setting a new value in the operation field.  If no value is choosen, the
+     * default operation for the platform will be selected (value is 1 &lt;&lt; 4).
+     *
+     * @see DropTargetListener#dragEnter
+     * @see DropTargetListener#dragOperationChanged
+     * @since 2.0
+     */
+    public const static int DROP_DEFAULT = 1 << 4;
+
+    /**
+     * DragSource Event: the drop has successfully completed or has been terminated (such as hitting
+     * the ESC key); perform cleanup such as removing data on a move operation (value is 2000).
+     */
+    public static const int DragEnd     = 2000;
+
+    /**
+     * DragSource Event: the data to be dropped is required from the drag source (value is 2001).
+     */
+    public static const int DragSetData = 2001;
+
+    /**
+     * DropTarget Event: the cursor has entered the drop target boundaries (value is 2002).
+     */
+    public static const int DragEnter   = 2002;
+
+    /**
+     * DropTarget Event: the cursor has left the drop target boundaries OR the drop
+     * operation has been cancelled (such as by hitting ECS) OR the drop is about to
+     * happen (user has released the mous ebutotn over this target) (value is 2003).
+     */
+    public static const int DragLeave   = 2003;
+
+    /**
+     * DropTarget Event: the cursor is over the drop target (value is 2004).
+     */
+    public static const int DragOver    = 2004;
+
+    /**
+     * DropTarget Event: the operation being performed has changed usually due to the user
+     * changing the selected modifier keys while dragging (value is 2005).
+     */
+    public static const int DragOperationChanged = 2005;
+
+    /**
+     * DropTarget Event: the data has been dropped (value is 2006).
+     */
+    public static const int Drop = 2006;
+
+    /**
+     * DropTarget Event: the drop target is given a last chance to modify the drop (value is 2007).
+     */
+    public static const int DropAccept  = 2007;
+
+    /**
+     * DragSource Event: a drag is about to begin (value is 2008).
+     */
+    public static const int DragStart = 2008;
+
+    /**
+     * DropTarget drag under effect: No effect is shown (value is 0).
+     */
+    public static const int FEEDBACK_NONE = 0;
+
+    /**
+     * DropTarget drag under effect: The item under the cursor is selected; applies to tables
+     * and trees (value is 1).
+     */
+    public static const int FEEDBACK_SELECT = 1;
+
+    /**
+     * DropTarget drag under effect: An insertion mark is shown before the item under the cursor; applies to
+     * trees (value is 2).
+     */
+    public static const int FEEDBACK_INSERT_BEFORE = 2;
+
+    /**
+     * DropTarget drag under effect:An insertion mark is shown after the item under the cursor; applies to
+     * trees (value is 4).
+     */
+    public static const int FEEDBACK_INSERT_AFTER = 4;
+
+    /**
+     * DropTarget drag under effect: The widget is scrolled up or down to allow the user to drop on items that
+     * are not currently visible;  applies to tables and trees (value is 8).
+     */
+    public static const int FEEDBACK_SCROLL = 8;
+
+    /**
+     * DropTarget drag under effect: The item currently under the cursor is expanded to allow the user to
+     * select a drop target from a sub item; applies to trees (value is 16).
+     */
+    public static const int FEEDBACK_EXPAND = 16;
+
+    /**
+     * Error code: drag source can not be initialized (value is 2000).
+     */
+    public static const int ERROR_CANNOT_INIT_DRAG = 2000;
+
+    /**
+     * Error code: drop target cannot be initialized (value is 2001).
+     */
+    public static const int ERROR_CANNOT_INIT_DROP = 2001;
+
+    /**
+     * Error code: Data can not be set on system clipboard (value is 2002).
+     */
+    public static const int ERROR_CANNOT_SET_CLIPBOARD = 2002;
+
+    /**
+     * Error code: Data does not have correct format for type (value is 2003).
+     * @since 3.1
+     */
+    public static const int ERROR_INVALID_DATA = 2003;
+
+
+    static const char[] INIT_DRAG_MESSAGE = "Cannot initialize Drag"; //$NON-NLS-1$
+    static const char[] INIT_DROP_MESSAGE = "Cannot initialize Drop"; //$NON-NLS-1$
+    static const char[] CANNOT_SET_CLIPBOARD_MESSAGE = "Cannot set data in clipboard"; //$NON-NLS-1$
+    static const char[] INVALID_DATA_MESSAGE = "Data does not have correct format for type"; //$NON-NLS-1$
+
+/**
+ * Throws an appropriate exception based on the passed in error code.
+ *
+ * @param code the DND error code
+ */
+public static void error (int code) {
+    error (code, 0);
+}
+
+/**
+ * Throws an appropriate exception based on the passed in error code.
+ * The <code>hresult</code> argument should be either 0, or the
+ * platform specific error code.
+ * <p>
+ * In DND, errors are reported by throwing one of three exceptions:
+ * <dl>
+ * <dd>java.lang.IllegalArgumentException</dd>
+ * <dt>thrown whenever one of the API methods is invoked with an illegal argument</dt>
+ * <dd>org.eclipse.swt.DWTException (extends java.lang.RuntimeException)</dd>
+ * <dt>thrown whenever a recoverable error happens internally in DWT</dt>
+ * <dd>org.eclipse.swt.DWTError (extends java.lang.Error)</dd>
+ * <dt>thrown whenever a <b>non-recoverable</b> error happens internally in DWT</dt>
+ * </dl>
+ * This method provides the logic which maps between error codes
+ * and one of the above exceptions.
+ * </p>
+ *
+ * @param code the DND error code.
+ * @param hresult the platform specific error code.
+ *
+ * @see DWTError
+ * @see DWTException
+ * @see IllegalArgumentException
+ */
+public static void error (int code, int hresult) {
+    switch (code) {
+        /* OS Failure/Limit (fatal, may occur only on some platforms) */
+        case DND.ERROR_CANNOT_INIT_DRAG:{
+            char[] msg = DND.INIT_DRAG_MESSAGE;
+            if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$
+            throw new DWTError (code, msg);
+        }
+        case DND.ERROR_CANNOT_INIT_DROP:{
+            char[] msg = DND.INIT_DROP_MESSAGE;
+            if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$
+            throw new DWTError (code, msg);
+        }
+        case DND.ERROR_CANNOT_SET_CLIPBOARD:{
+            char[] msg = DND.CANNOT_SET_CLIPBOARD_MESSAGE;
+            if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$
+            throw new DWTError (code, msg);
+        }
+        case DND.ERROR_INVALID_DATA:{
+            char[] msg = DND.INVALID_DATA_MESSAGE;
+            if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$
+            throw new DWTException (code, msg);
+        }
+        default:
+    }
+
+    /* Unknown/Undefined Error */
+    DWT.error(code);
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DNDEvent.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DNDEvent;
+
+
+
+import dwt.graphics.Image;
+import dwt.widgets.Event;
+import dwt.dnd.TransferData;
+
+class DNDEvent : Event {
+    public TransferData dataType;
+    public TransferData[] dataTypes;
+    public int operations;
+    public int feedback;
+    public Image image;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DNDListener.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DNDListener;
+
+
+import dwt.internal.DWTEventListener;
+import dwt.widgets.Event;
+import dwt.widgets.TypedListener;
+import dwt.widgets.Widget;
+import dwt.dnd.DND;
+import dwt.dnd.DNDEvent;
+import dwt.dnd.DragSourceEvent;
+import dwt.dnd.DragSourceEffect;
+import dwt.dnd.DragSource;
+import dwt.dnd.DragSourceListener;
+import dwt.dnd.DropTargetEvent;
+import dwt.dnd.DropTargetListener;
+import dwt.dnd.DropTargetEffect;
+import dwt.dnd.DropTarget;
+
+
+class DNDListener : TypedListener {
+    Widget dndWidget;
+/**
+ * DNDListener constructor comment.
+ * @param listener org.eclipse.swt.internal.DWTEventListener
+ */
+this(DWTEventListener listener) {
+    super(listener);
+}
+public override void handleEvent (Event e) {
+    switch (e.type) {
+        case DND.DragStart: {
+            DragSourceEvent event = new DragSourceEvent(cast(DNDEvent)e);
+            DragSourceEffect sourceEffect = (cast(DragSource) dndWidget).getDragSourceEffect();
+            if (sourceEffect !is null) {
+                sourceEffect.dragStart (event);
+            }
+            (cast(DragSourceListener) eventListener).dragStart (event);
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragEnd: {
+            DragSourceEvent event = new DragSourceEvent(cast(DNDEvent)e);
+            DragSourceEffect sourceEffect = (cast(DragSource) dndWidget).getDragSourceEffect();
+            if (sourceEffect !is null) {
+                sourceEffect.dragFinished (event);
+            }
+            (cast(DragSourceListener) eventListener).dragFinished (event);
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragSetData: {
+            DragSourceEvent event = new DragSourceEvent(cast(DNDEvent)e);
+            DragSourceEffect sourceEffect = (cast(DragSource) dndWidget).getDragSourceEffect();
+            if (sourceEffect !is null) {
+                sourceEffect.dragSetData (event);
+            }
+            (cast(DragSourceListener) eventListener).dragSetData (event);
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragEnter: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).dragEnter (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.dragEnter (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragLeave: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).dragLeave (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.dragLeave (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragOver: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).dragOver (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.dragOver (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.Drop: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).drop (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.drop (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DropAccept: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).dropAccept (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.dropAccept (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragOperationChanged: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).dragOperationChanged (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.dragOperationChanged (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        default:
+
+    }
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DragSource.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,654 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DragSource;
+
+
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.DWTException;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.internal.ImageList;
+import dwt.internal.ole.win32.COM;
+import dwt.internal.win32.OS;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.Table;
+import dwt.widgets.Tree;
+import dwt.widgets.Widget;
+
+/**
+ *
+ * <code>DragSource</code> defines the source object for a drag and drop transfer.
+ *
+ * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
+ *
+ * <p>A drag source is the object which originates a drag and drop operation. For the specified widget,
+ * it defines the type of data that is available for dragging and the set of operations that can
+ * be performed on that data.  The operations can be any bit-wise combination of DND.MOVE, DND.COPY or
+ * DND.LINK.  The type of data that can be transferred is specified by subclasses of Transfer such as
+ * TextTransfer or FileTransfer.  The type of data transferred can be a predefined system type or it
+ * can be a type defined by the application.  For instructions on how to define your own transfer type,
+ * refer to <code>ByteArrayTransfer</code>.</p>
+ *
+ * <p>You may have several DragSources in an application but you can only have one DragSource
+ * per Control.  Data dragged from this DragSource can be dropped on a site within this application
+ * or it can be dropped on another application such as an external Text editor.</p>
+ *
+ * <p>The application supplies the content of the data being transferred by implementing the
+ * <code>DragSourceListener</code> and associating it with the DragSource via DragSource#addDragListener.</p>
+ *
+ * <p>When a successful move operation occurs, the application is required to take the appropriate
+ * action to remove the data from its display and remove any associated operating system resources or
+ * internal references.  Typically in a move operation, the drop target makes a copy of the data
+ * and the drag source deletes the original.  However, sometimes copying the data can take a long
+ * time (such as copying a large file).  Therefore, on some platforms, the drop target may actually
+ * move the data in the operating system rather than make a copy.  This is usually only done in
+ * file transfers.  In this case, the drag source is informed in the DragEnd event that a
+ * DROP_TARGET_MOVE was performed.  It is the responsibility of the drag source at this point to clean
+ * up its displayed information.  No action needs to be taken on the operating system resources.</p>
+ *
+ * <p> The following example shows a Label widget that allows text to be dragged from it.</p>
+ *
+ * <code><pre>
+ *  // Enable a label as a Drag Source
+ *  Label label = new Label(shell, DWT.NONE);
+ *  // This example will allow text to be dragged
+ *  Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
+ *  // This example will allow the text to be copied or moved to the drop target
+ *  int operations = DND.DROP_MOVE | DND.DROP_COPY;
+ *
+ *  DragSource source = new DragSource(label, operations);
+ *  source.setTransfer(types);
+ *  source.addDragListener(new DragSourceListener() {
+ *      public void dragStart(DragSourceEvent e) {
+ *          // Only start the drag if there is actually text in the
+ *          // label - this text will be what is dropped on the target.
+ *          if (label.getText().length() is 0) {
+ *              event.doit = false;
+ *          }
+ *      };
+ *      public void dragSetData(DragSourceEvent event) {
+ *          // A drop has been performed, so provide the data of the
+ *          // requested type.
+ *          // (Checking the type of the requested data is only
+ *          // necessary if the drag source supports more than
+ *          // one data type but is shown here as an example).
+ *          if (TextTransfer.getInstance().isSupportedType(event.dataType)){
+ *              event.data = label.getText();
+ *          }
+ *      }
+ *      public void dragFinished(DragSourceEvent event) {
+ *          // A Move operation has been performed so remove the data
+ *          // from the source
+ *          if (event.detail is DND.DROP_MOVE)
+ *              label.setText("");
+ *      }
+ *  });
+ * </pre></code>
+ *
+ *
+ * <dl>
+ *  <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd>
+ *  <dt><b>Events</b></dt> <dd>DND.DragStart, DND.DragSetData, DND.DragEnd</dd>
+ * </dl>
+ */
+public class DragSource : Widget {
+
+    // info for registering as a drag source
+    Control control;
+    Listener controlListener;
+    Transfer[] transferAgents = new Transfer[0];
+    DragSourceEffect dragEffect;
+    Composite topControl;
+
+    // ole interfaces
+    COMObject iDropSource;
+    COMObject iDataObject;
+    int refCount;
+
+    //workaround - track the operation performed by the drop target for DragEnd event
+    int dataEffect = DND.DROP_NONE;
+
+    static final String DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$
+    static final String DRAGSOURCEID = "DragSource"; //$NON-NLS-1$
+    static final int CFSTR_PERFORMEDDROPEFFECT  = Transfer.registerType("Performed DropEffect");     //$NON-NLS-1$
+
+/**
+ * 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 DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ * @exception DWTError <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</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_INIT_DRAG should be an DWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ *
+ * @see Widget#dispose
+ * @see DragSource#checkSubclass
+ * @see DND#DROP_NONE
+ * @see DND#DROP_COPY
+ * @see DND#DROP_MOVE
+ * @see DND#DROP_LINK
+ */
+public this(Control control, int style) {
+    super(control, checkStyle(style));
+    this.control = control;
+    if (control.getData(DRAGSOURCEID) !is null) {
+        DND.error(DND.ERROR_CANNOT_INIT_DRAG);
+    }
+    control.setData(DRAGSOURCEID, this);
+    createCOMInterfaces();
+    this.AddRef();
+
+    controlListener = new Listener() {
+        public void handleEvent(Event event) {
+            if (event.type is DWT.Dispose) {
+                if (!DragSource.this.isDisposed()) {
+                    DragSource.this.dispose();
+                }
+            }
+            if (event.type is DWT.DragDetect) {
+                if (!DragSource.this.isDisposed()) {
+                    DragSource.this.drag(event);
+                }
+            }
+        }
+    };
+    control.addListener(DWT.Dispose, controlListener);
+    control.addListener(DWT.DragDetect, controlListener);
+
+    this.addListener(DWT.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);
+    }
+}
+
+static int checkStyle(int style) {
+    if (style is DWT.NONE) return DND.DROP_MOVE;
+    return style;
+}
+
+/**
+ * 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></p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DragSourceListener
+ * @see #removeDragListener
+ * @see DragSourceEvent
+ */
+public void addDragListener(DragSourceListener listener) {
+    if (listener is null) DND.error(DWT.ERROR_NULL_ARGUMENT);
+    DNDListener typedListener = new DNDListener(listener);
+    typedListener.dndWidget = this;
+    addListener(DND.DragStart, typedListener);
+    addListener(DND.DragSetData, typedListener);
+    addListener(DND.DragEnd, typedListener);
+}
+
+private int AddRef() {
+    refCount++;
+    return refCount;
+}
+
+private void createCOMInterfaces() {
+    // register each of the interfaces that this object implements
+    iDropSource = new COMObject(new int[]{2, 0, 0, 2, 1}){
+        public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
+        public int method1(int[] args) {return AddRef();}
+        public int method2(int[] args) {return Release();}
+        public int method3(int[] args) {return QueryContinueDrag(args[0], args[1]);}
+        public int method4(int[] args) {return GiveFeedback(args[0]);}
+    };
+
+    iDataObject = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 2, 3, 2, 4, 1, 1}){
+        public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
+        public int method1(int[] args) {return AddRef();}
+        public int method2(int[] args) {return Release();}
+        public int method3(int[] args) {return GetData(args[0], args[1]);}
+        // method4 GetDataHere - not implemented
+        public int method5(int[] args) {return QueryGetData(args[0]);}
+        // method6 GetCanonicalFormatEtc - not implemented
+        public int method7(int[] args) {return SetData(args[0], args[1], args[2]);}
+        public int method8(int[] args) {return EnumFormatEtc(args[0], args[1]);}
+        // method9 DAdvise - not implemented
+        // method10 DUnadvise - not implemented
+        // method11 EnumDAdvise - not implemented
+    };
+}
+
+protected void checkSubclass() {
+    String name = getClass().getName();
+    String validName = DragSource.class.getName();
+    if (!validName.equals(name)) {
+        DND.error(DWT.ERROR_INVALID_SUBCLASS);
+    }
+}
+
+private void disposeCOMInterfaces() {
+    if (iDropSource !is null)
+        iDropSource.dispose();
+    iDropSource = null;
+
+    if (iDataObject !is null)
+        iDataObject.dispose();
+    iDataObject = null;
+}
+
+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 is null || transferAgents.length is 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, new bool(true));
+    ImageList imagelist = null;
+    Image image = event.image;
+    if (image !is null) {
+        imagelist = new ImageList(DWT.NONE);
+        imagelist.add(image);
+        topControl = control.getShell();
+        OS.ImageList_BeginDrag(imagelist.getHandle(), 0, 0, 0);
+        Point location = topControl.getLocation();
+        /*
+        * 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);
+        }
+        OS.ImageList_DragEnter(topControl.handle, dragEvent.x - location.x, dragEvent.y - location.y);
+    }
+    int result = COM.DoDragDrop(iDataObject.getAddress(), iDropSource.getAddress(), operations, pdwEffect);
+    if (imagelist !is null) {
+        OS.ImageList_DragLeave(topControl.handle);
+        OS.ImageList_EndDrag();
+        imagelist.dispose();
+        topControl = null;
+    }
+    display.setData(key, oldValue);
+    int operation = osToOp(pdwEffect[0]);
+    if (dataEffect is DND.DROP_MOVE) {
+        operation = (operation is DND.DROP_NONE || operation is DND.DROP_COPY) ? DND.DROP_TARGET_MOVE : DND.DROP_MOVE;
+    } else {
+        if (dataEffect !is DND.DROP_NONE) {
+            operation = dataEffect;
+        }
+    }
+    event = new DNDEvent();
+    event.widget = this;
+    event.time = OS.GetMessageTime();
+    event.doit = (result is COM.DRAGDROP_S_DROP);
+    event.detail = operation;
+    notifyListeners(DND.DragEnd,event);
+    dataEffect = DND.DROP_NONE;
+}
+/*
+ * EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
+ * Ownership of ppenumFormatetc transfers from callee to caller so reference count on ppenumFormatetc
+ * must be incremented before returning.  Caller is responsible for releasing ppenumFormatetc.
+ */
+private int EnumFormatEtc(int dwDirection, int ppenumFormatetc) {
+    // only allow getting of data - SetData is not currently supported
+    if (dwDirection is COM.DATADIR_SET) return COM.E_NOTIMPL;
+
+    // what types have been registered?
+    TransferData[] allowedDataTypes = new TransferData[0];
+    for (int i = 0; i < transferAgents.length; i++){
+        Transfer transferAgent = transferAgents[i];
+        if (transferAgent !is null) {
+            TransferData[] formats = transferAgent.getSupportedTypes();
+            TransferData[] newAllowedDataTypes = new TransferData[allowedDataTypes.length + formats.length];
+            System.arraycopy(allowedDataTypes, 0, newAllowedDataTypes, 0, allowedDataTypes.length);
+            System.arraycopy(formats, 0, newAllowedDataTypes, allowedDataTypes.length, formats.length);
+            allowedDataTypes = newAllowedDataTypes;
+        }
+    }
+
+    OleEnumFORMATETC enumFORMATETC = new OleEnumFORMATETC();
+    enumFORMATETC.AddRef();
+
+    FORMATETC[] formats = new FORMATETC[allowedDataTypes.length];
+    for (int i = 0; i < formats.length; i++){
+        formats[i] = allowedDataTypes[i].formatetc;
+    }
+    enumFORMATETC.setFormats(formats);
+
+    OS.MoveMemory(ppenumFormatetc, new int[] {enumFORMATETC.getAddress()}, 4);
+    return COM.S_OK;
+}
+/**
+ * Returns the Control which is registered for this DragSource.  This is the control that the
+ * user clicks in to initiate dragging.
+ *
+ * @return the Control which is registered for this DragSource
+ */
+public Control getControl() {
+    return control;
+}
+
+private int GetData(int pFormatetc, int pmedium) {
+    /* Called by a data consumer to obtain data from a source data object.
+       The GetData method renders the data described in the specified FORMATETC
+       structure and transfers it through the specified STGMEDIUM structure.
+       The caller then assumes responsibility for releasing the STGMEDIUM structure.
+    */
+    if (pFormatetc is 0 || pmedium is 0) return COM.E_INVALIDARG;
+
+    if (QueryGetData(pFormatetc) !is COM.S_OK) return COM.DV_E_FORMATETC;
+
+    TransferData transferData = new TransferData();
+    transferData.formatetc = new FORMATETC();
+    COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
+    transferData.type = transferData.formatetc.cfFormat;
+    transferData.stgmedium = new STGMEDIUM();
+    transferData.result = COM.E_FAIL;
+
+    DNDEvent event = new DNDEvent();
+    event.widget = this;
+    event.time = OS.GetMessageTime();
+    event.dataType = transferData;
+    notifyListeners(DND.DragSetData,event);
+
+    // get matching transfer agent to perform conversion
+    Transfer transfer = null;
+    for (int i = 0; i < transferAgents.length; i++){
+        Transfer transferAgent = transferAgents[i];
+        if (transferAgent !is null && transferAgent.isSupportedType(transferData)){
+            transfer = transferAgent;
+            break;
+        }
+    }
+
+    if (transfer is null) return COM.DV_E_FORMATETC;
+    transfer.javaToNative(event.data, transferData);
+    if (transferData.result !is COM.S_OK) return transferData.result;
+    COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof);
+    return transferData.result;
+}
+
+/**
+ * Returns the drag effect that is registered for this DragSource.  This drag
+ * effect will be used during a drag and drop operation.
+ *
+ * @return the drag effect that is registered for this DragSource
+ *
+ * @since 3.3
+ */
+public DragSourceEffect getDragSourceEffect() {
+    return dragEffect;
+}
+
+/**
+ * Returns the list of data types that can be transferred by this DragSource.
+ *
+ * @return the list of data types that can be transferred by this DragSource
+ */
+public Transfer[] getTransfer(){
+    return transferAgents;
+}
+
+private int GiveFeedback(int dwEffect) {
+    return COM.DRAGDROP_S_USEDEFAULTCURSORS;
+}
+
+private int QueryContinueDrag(int fEscapePressed, int grfKeyState) {
+    if (fEscapePressed !is 0){
+        if (topControl !is null) OS.ImageList_DragLeave(topControl.handle);
+        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) is 0) {
+        if (topControl !is null) OS.ImageList_DragLeave(topControl.handle);
+        return COM.DRAGDROP_S_DROP;
+    }
+
+    if (topControl !is null) {
+        Display display = getDisplay();
+        Point pt = display.getCursorLocation();
+        Point location = topControl.getLocation();
+        OS.ImageList_DragMove(pt.x - location.x, pt.y - location.y);
+    }
+    return COM.S_OK;
+}
+
+private void onDispose() {
+    if (control is null) return;
+    this.Release();
+    if (controlListener !is null){
+        control.removeListener(DWT.Dispose, controlListener);
+        control.removeListener(DWT.DragDetect, controlListener);
+    }
+    controlListener = null;
+    control.setData(DRAGSOURCEID, null);
+    control = null;
+    transferAgents = null;
+}
+
+private int opToOs(int operation) {
+    int osOperation = 0;
+    if ((operation & DND.DROP_COPY) !is 0){
+        osOperation |= COM.DROPEFFECT_COPY;
+    }
+    if ((operation & DND.DROP_LINK) !is 0) {
+        osOperation |= COM.DROPEFFECT_LINK;
+    }
+    if ((operation & DND.DROP_MOVE) !is 0) {
+        osOperation |= COM.DROPEFFECT_MOVE;
+    }
+    return osOperation;
+}
+
+private int osToOp(int osOperation){
+    int operation = 0;
+    if ((osOperation & COM.DROPEFFECT_COPY) !is 0){
+        operation |= DND.DROP_COPY;
+    }
+    if ((osOperation & COM.DROPEFFECT_LINK) !is 0) {
+        operation |= DND.DROP_LINK;
+    }
+    if ((osOperation & COM.DROPEFFECT_MOVE) !is 0) {
+        operation |= DND.DROP_MOVE;
+    }
+    return operation;
+}
+
+private int QueryGetData(int pFormatetc) {
+    if (transferAgents is null) return COM.E_FAIL;
+    TransferData transferData = new TransferData();
+    transferData.formatetc = new FORMATETC();
+    COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
+    transferData.type = transferData.formatetc.cfFormat;
+
+    // is this type supported by the transfer agent?
+    for (int i = 0; i < transferAgents.length; i++){
+        Transfer transfer = transferAgents[i];
+        if (transfer !is null && transfer.isSupportedType(transferData))
+            return COM.S_OK;
+    }
+
+    return COM.DV_E_FORMATETC;
+}
+
+/* QueryInterface([in] riid, [out] ppvObject)
+ * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
+ * must be incremented before returning.  Caller is responsible for releasing ppvObject.
+ */
+private int QueryInterface(int riid, int ppvObject) {
+    if (riid is 0 || ppvObject is 0)
+        return COM.E_INVALIDARG;
+    GUID guid = new GUID();
+    COM.MoveMemory(guid, riid, GUID.sizeof);
+
+    if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDropSource)) {
+        OS.MoveMemory(ppvObject, new int[] {iDropSource.getAddress()}, 4);
+        AddRef();
+        return COM.S_OK;
+    }
+
+    if (COM.IsEqualGUID(guid, COM.IIDIDataObject) ) {
+        OS.MoveMemory(ppvObject, new int[] {iDataObject.getAddress()}, 4);
+        AddRef();
+        return COM.S_OK;
+    }
+
+    OS.MoveMemory(ppvObject, new int[] {0}, 4);
+    return COM.E_NOINTERFACE;
+}
+
+private int Release() {
+    refCount--;
+    if (refCount is 0) {
+        disposeCOMInterfaces();
+        COM.CoFreeUnusedLibraries();
+    }
+    return refCount;
+}
+
+/**
+ * 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 be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DragSourceListener
+ * @see #addDragListener
+ */
+public void removeDragListener(DragSourceListener listener) {
+    if (listener is null) DND.error(DWT.ERROR_NULL_ARGUMENT);
+    removeListener(DND.DragStart, listener);
+    removeListener(DND.DragSetData, listener);
+    removeListener(DND.DragEnd, listener);
+}
+
+private int SetData(int pFormatetc, int pmedium, int fRelease) {
+    if (pFormatetc is 0 || pmedium is 0) return COM.E_INVALIDARG;
+    FORMATETC formatetc = new FORMATETC();
+    COM.MoveMemory(formatetc, pFormatetc, FORMATETC.sizeof);
+    if (formatetc.cfFormat is CFSTR_PERFORMEDDROPEFFECT && formatetc.tymed is COM.TYMED_HGLOBAL) {
+        STGMEDIUM stgmedium = new STGMEDIUM();
+        COM.MoveMemory(stgmedium, pmedium,STGMEDIUM.sizeof);
+        int[] ptrEffect = new int[1];
+        OS.MoveMemory(ptrEffect, stgmedium.unionField,4);
+        int[] effect = new int[1];
+        OS.MoveMemory(effect, ptrEffect[0],4);
+        dataEffect = osToOp(effect[0]);
+    }
+    if (fRelease is 1) {
+        COM.ReleaseStgMedium(pmedium);
+    }
+    return COM.S_OK;
+}
+
+/**
+ * Specifies the drag effect for this DragSource.  This drag effect will be
+ * used during a drag and drop operation.
+ *
+ * @param effect the drag effect that is registered for this DragSource
+ *
+ * @since 3.3
+ */
+public void setDragSourceEffect(DragSourceEffect effect) {
+    dragEffect = effect;
+}
+
+/**
+ * Specifies the list of data types that can be transferred by this DragSource.
+ * The application must be able to provide data to match each of these types when
+ * a successful drop has occurred.
+ *
+ * @param transferAgents a list of Transfer objects which define the types of data that can be
+ * dragged from this source
+ */
+public void setTransfer(Transfer[] transferAgents){
+    this.transferAgents = transferAgents;
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DragSourceAdapter.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DragSourceAdapter;
+
+import dwt.dnd.DragSourceListener;
+import dwt.dnd.DragSourceEvent;
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the <code>DragSourceListener</code> interface.
+ *
+ * <p>Classes that wish to deal with <code>DragSourceEvent</code>s can
+ * extend this class and override only the methods which they are
+ * interested in.</p>
+ *
+ * @see DragSourceListener
+ * @see DragSourceEvent
+ */
+public class DragSourceAdapter : DragSourceListener {
+    /**
+     * This implementation of <code>dragStart</code> permits the drag operation to start.
+     * For additional information see <code>DragSourceListener.dragStart</code>.
+     */
+    public void dragStart(DragSourceEvent event){}
+    /**
+     * This implementation of <code>dragFinished</code> does nothing.
+     * For additional information see <code>DragSourceListener.dragFinished</code>.
+     */
+    public void dragFinished(DragSourceEvent event){}
+    /**
+     * This implementation of <code>dragSetData</code> does nothing.
+     * For additional information see <code>DragSourceListener.dragSetData</code>.
+     */
+    public void dragSetData(DragSourceEvent event){}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DragSourceEffect.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DragSourceEffect;
+
+
+import dwt.DWT;
+import dwt.widgets.Control;
+import dwt.dnd.DragSourceAdapter;
+
+/**
+ * This class provides default implementations to display a drag source
+ * effect during a drag and drop operation. The current implementation
+ * does not provide any visual feedback.
+ *
+ * <p>The drag source effect has the same API as the
+ * <code>DragSourceAdapter</code> so that it can provide custom visual
+ * feedback when a <code>DragSourceEvent</code> occurs.
+ * </p>
+ *
+ * <p>Classes that wish to provide their own drag source effect such as
+ * displaying a default source image during a drag can extend the <code>DragSourceEffect</code>
+ * class, override the <code>DragSourceAdapter.dragStart</code> method and set
+ * the field <code>DragSourceEvent.image</code> with their own image.
+ * The image should be disposed when <code>DragSourceAdapter.dragFinished</code> is called.
+ * </p>
+ *
+ * @see DragSourceAdapter
+ * @see DragSourceEvent
+ *
+ * @since 3.3
+ */
+public class DragSourceEffect : DragSourceAdapter {
+    Control control = null;
+
+    /**
+     * Creates a new <code>DragSourceEffect</code> to handle drag effect from the specified <code>Control</code>.
+     *
+     * @param control the <code>Control</code> that the user clicks on to initiate the drag
+     *
+     * @exception IllegalArgumentException <ul>
+     *    <li>ERROR_NULL_ARGUMENT - if the control is null</li>
+     * </ul>
+     */
+    public this(Control control) {
+        if (control is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+        this.control = control;
+    }
+
+    /**
+     * Returns the Control which is registered for this DragSourceEffect.  This is the control that the
+     * user clicks in to initiate dragging.
+     *
+     * @return the Control which is registered for this DragSourceEffect
+     */
+    public Control getControl() {
+        return control;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DragSourceEvent.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DragSourceEvent;
+
+
+import dwt.events.TypedEvent;
+import dwt.widgets.Event;
+import dwt.graphics.Image;
+import dwt.dnd.TransferData;
+import dwt.dnd.DNDEvent;
+
+/**
+ * The DragSourceEvent contains the event information passed in the methods of the DragSourceListener.
+ *
+ * @see DragSourceListener
+ */
+public class DragSourceEvent : TypedEvent {
+    /**
+     * The operation that was performed.
+     * @see DND#DROP_NONE
+     * @see DND#DROP_MOVE
+     * @see DND#DROP_COPY
+     * @see DND#DROP_LINK
+     * @see DND#DROP_TARGET_MOVE
+     */
+    public int detail;
+
+    /**
+     * In dragStart, the doit field determines if the drag and drop operation
+     * should proceed; in dragFinished, the doit field indicates whether
+     * the operation was performed successfully.
+     * <p></p>
+     * In dragStart:
+     * <p>Flag to determine if the drag and drop operation should proceed.
+     * The application can set this value to false to prevent the drag from starting.
+     * Set to true by default.</p>
+     *
+     * <p>In dragFinished:</p>
+     * <p>Flag to indicate if the operation was performed successfully.
+     * True if the operation was performed successfully.</p>
+     */
+    public bool doit;
+
+    /**
+     * In dragStart, the x coordinate (relative to the control) of the
+     * position the mouse went down to start the drag.
+     * @since 3.2
+     */
+    public int x;
+    /**
+     * In dragStart, the y coordinate (relative to the control) of the
+     * position the mouse went down to start the drag .
+     * @since 3.2
+     */
+    public int y;
+
+    /**
+     * The type of data requested.
+     * Data provided in the data field must be of the same type.
+     */
+    public TransferData dataType;
+
+    /**
+     * The drag source image to be displayed during the drag.
+     * <p>A value of null indicates that no drag image will be displayed.</p>
+     * <p>The default value is null.</p>
+     *
+     * @since 3.3
+     */
+    public Image image;
+
+    static const long serialVersionUID = 3257002142513770808L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public this(DNDEvent e) {
+    super( cast(Event) e );
+    this.data = e.data;
+    this.detail = e.detail;
+    this.doit = e.doit;
+    this.dataType = e.dataType;
+    this.x = e.x;
+    this.y = e.y;
+    this.image = e.image;
+}
+void updateEvent(DNDEvent e) {
+    e.widget = this.widget;
+    e.time = this.time;
+    e.data = this.data;
+    e.detail = this.detail;
+    e.doit = this.doit;
+    e.dataType = this.dataType;
+    e.x = this.x;
+    e.y = this.y;
+    e.image = this.image;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DragSourceListener.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DragSourceListener;
+
+import dwt.internal.DWTEventListener;
+import dwt.dnd.DragSourceEvent;
+
+/**
+ * The <code>DragSourceListener</code> class provides event notification to the application for DragSource events.
+ *
+ * <p>When the user drops data on a <code>DropTarget</code>, the application which defines the <code>DragSource</code>
+ * must provide the dropped data by implementing <code>dragSetData</code>.  In the dragSetData, the application
+ * must support all the data types that were specified in the DragSource#setTransfer method.</p>
+ *
+ * <p>After the drop has completed successfully or has been aborted, the application which defines the
+ * <code>DragSource</code> is required to take the appropriate cleanup action.  In the case of a successful
+ * <b>move</b> operation, the application must remove the data that was transferred.</p>
+ *
+ */
+public interface DragSourceListener : DWTEventListener {
+
+/**
+ * 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.
+ *
+ * <p>The following fields in the DragSourceEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in,out)doit
+ * </ul></p>
+ *
+ * @param event the information associated with the drag start event
+ *
+ * @see DragSourceEvent
+ */
+public void dragStart(DragSourceEvent event);
+
+/**
+ * The data is required from the drag source.
+ *
+ * <p>The following fields in the DragSourceEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)dataType - the type of data requested.
+ * <li>(out)data    - the application inserts the actual data here (must match the dataType)
+ * </ul></p>
+ *
+ * @param event the information associated with the drag set data event
+ *
+ * @see DragSourceEvent
+ */
+public void dragSetData(DragSourceEvent event);
+
+/**
+ * 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.
+ *
+ * <p>The following fields in the DragSourceEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)doit
+ * <li>(in)detail
+ * </ul></p>
+ *
+ * @param event the information associated with the drag finished event
+ *
+ * @see DragSourceEvent
+ */
+public void dragFinished(DragSourceEvent event);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DropTarget.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,709 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DropTarget;
+
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.DWTException;
+import dwt.internal.ole.win32.COM;
+import dwt.internal.win32.OS;
+import dwt.widgets.Control;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.Table;
+import dwt.widgets.Tree;
+import dwt.widgets.Widget;
+
+/**
+ *
+ * Class <code>DropTarget</code> defines the target object for a drag and drop transfer.
+ *
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ *
+ * <p>This class identifies the <code>Control</code> over which the user must position the cursor
+ * in order to drop the data being transferred.  It also specifies what data types can be dropped on
+ * this control and what operations can be performed.  You may have several DropTragets in an
+ * application but there can only be a one to one mapping between a <code>Control</code> and a <code>DropTarget</code>.
+ * The DropTarget can receive data from within the same application or from other applications
+ * (such as text dragged from a text editor like Word).</p>
+ *
+ * <code><pre>
+ *  int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK;
+ *  Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
+ *  DropTarget target = new DropTarget(label, operations);
+ *  target.setTransfer(types);
+ * </code></pre>
+ *
+ * <p>The application is notified of data being dragged over this control and of when a drop occurs by
+ * implementing the interface <code>DropTargetListener</code> which uses the class
+ * <code>DropTargetEvent</code>.  The application can modify the type of drag being performed
+ * on this Control at any stage of the drag by modifying the <code>event.detail</code> field or the
+ * <code>event.currentDataType</code> field.  When the data is dropped, it is the responsibility of
+ * the application to copy this data for its own purposes.
+ *
+ * <code><pre>
+ *  target.addDropListener (new DropTargetListener() {
+ *      public void dragEnter(DropTargetEvent event) {};
+ *      public void dragOver(DropTargetEvent event) {};
+ *      public void dragLeave(DropTargetEvent event) {};
+ *      public void dragOperationChanged(DropTargetEvent event) {};
+ *      public void dropAccept(DropTargetEvent event) {}
+ *      public void drop(DropTargetEvent event) {
+ *          // A drop has occurred, copy over the data
+ *          if (event.data is null) { // no data to copy, indicate failure in event.detail
+ *              event.detail = DND.DROP_NONE;
+ *              return;
+ *          }
+ *          label.setText ((String) event.data); // data copied to label text
+ *      }
+ *  });
+ * </pre></code>
+ *
+ * <dl>
+ *  <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd>
+ *  <dt><b>Events</b></dt> <dd>DND.DragEnter, DND.DragLeave, DND.DragOver, DND.DragOperationChanged,
+ *                             DND.DropAccept, DND.Drop </dd>
+ * </dl>
+ */
+public class DropTarget : Widget {
+
+    Control control;
+    Listener controlListener;
+    Transfer[] transferAgents = new Transfer[0];
+    DropTargetEffect dropEffect;
+
+    // Track application selections
+    TransferData selectedDataType;
+    int selectedOperation;
+
+    // workaround - There is no event for "operation changed" so track operation based on key state
+    int keyOperation = -1;
+
+    // workaround - The dataobject address is only passed as an argument in drag enter and drop.
+    // To allow applications to query the data values during the drag over operations,
+    // maintain a reference to it.
+    IDataObject iDataObject;
+
+    // interfaces
+    COMObject iDropTarget;
+    int refCount;
+
+    static final String DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$
+    static final String DROPTARGETID = "DropTarget"; //$NON-NLS-1$
+
+/**
+ * Creates a new <code>DropTarget</code> to allow data to be dropped on the specified
+ * <code>Control</code>.
+ * Creating an instance of a DropTarget may cause system resources to be allocated
+ * depending on the platform.  It is therefore mandatory that the DropTarget instance
+ * be disposed when no longer required.
+ *
+ * @param control the <code>Control</code> over which the user positions the cursor to drop the data
+ * @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 DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ * @exception DWTError <ul>
+ *    <li>ERROR_CANNOT_INIT_DROP - unable to initiate drop target; this will occur if more than one
+ *        drop target is created for a control or if the operating system will not allow the creation
+ *        of the drop target</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_INIT_DROP should be an DWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ *
+ * @see Widget#dispose
+ * @see DropTarget#checkSubclass
+ * @see DND#DROP_NONE
+ * @see DND#DROP_COPY
+ * @see DND#DROP_MOVE
+ * @see DND#DROP_LINK
+ */
+public this(Control control, int style) {
+    super (control, checkStyle(style));
+    this.control = control;
+    if (control.getData(DROPTARGETID) !is null) {
+        DND.error(DND.ERROR_CANNOT_INIT_DROP);
+    }
+    control.setData(DROPTARGETID, this);
+    createCOMInterfaces();
+    this.AddRef();
+
+    if (COM.CoLockObjectExternal(iDropTarget.getAddress(), true, true) !is COM.S_OK)
+        DND.error(DND.ERROR_CANNOT_INIT_DROP);
+    if (COM.RegisterDragDrop( control.handle, iDropTarget.getAddress()) !is COM.S_OK)
+        DND.error(DND.ERROR_CANNOT_INIT_DROP);
+
+    controlListener = new Listener () {
+        public void handleEvent (Event event) {
+            if (!DropTarget.this.isDisposed()){
+                DropTarget.this.dispose();
+            }
+        }
+    };
+    control.addListener (DWT.Dispose, controlListener);
+
+    this.addListener(DWT.Dispose, new Listener () {
+        public void handleEvent (Event event) {
+            onDispose();
+        }
+    });
+
+    Object effect = control.getData(DEFAULT_DROP_TARGET_EFFECT);
+    if (effect instanceof DropTargetEffect) {
+        dropEffect = (DropTargetEffect) effect;
+    } else if (control instanceof Table) {
+        dropEffect = new TableDropTargetEffect((Table) control);
+    } else if (control instanceof Tree) {
+        dropEffect = new TreeDropTargetEffect((Tree) control);
+    }
+}
+
+static int checkStyle (int style) {
+    if (style is DWT.NONE) return DND.DROP_MOVE;
+    return style;
+}
+
+/**
+ * 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>DropTargetListener</code>
+ * interface.
+ *
+ * <p><ul>
+ * <li><code>dragEnter</code> is called when the cursor has entered the drop target boundaries
+ * <li><code>dragLeave</code> is called when the cursor has left the drop target boundaries and just before
+ * the drop occurs or is cancelled.
+ * <li><code>dragOperationChanged</code> is called when the operation being performed has changed
+ * (usually due to the user changing the selected modifier key(s) while dragging)
+ * <li><code>dragOver</code> is called when the cursor is moving over the drop target
+ * <li><code>dropAccept</code> is called just before the drop is performed.  The drop target is given
+ * the chance to change the nature of the drop or veto the drop by setting the <code>event.detail</code> field
+ * <li><code>drop</code> is called when the data is being dropped
+ * </ul></p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DropTargetListener
+ * @see #removeDropListener
+ * @see DropTargetEvent
+ */
+public void addDropListener(DropTargetListener listener) {
+    if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT);
+    DNDListener typedListener = new DNDListener (listener);
+    typedListener.dndWidget = this;
+    addListener (DND.DragEnter, typedListener);
+    addListener (DND.DragLeave, typedListener);
+    addListener (DND.DragOver, typedListener);
+    addListener (DND.DragOperationChanged, typedListener);
+    addListener (DND.Drop, typedListener);
+    addListener (DND.DropAccept, typedListener);
+}
+
+int AddRef() {
+    refCount++;
+    return refCount;
+}
+
+protected void checkSubclass () {
+    String name = getClass().getName ();
+    String validName = DropTarget.class.getName();
+    if (!validName.equals(name)) {
+        DND.error (DWT.ERROR_INVALID_SUBCLASS);
+    }
+}
+
+void createCOMInterfaces() {
+    // register each of the interfaces that this object implements
+    iDropTarget = new COMObject(new int[]{2, 0, 0, 5, 4, 0, 5}){
+        public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
+        public int method1(int[] args) {return AddRef();}
+        public int method2(int[] args) {return Release();}
+        public int method3(int[] args) {return DragEnter(args[0], args[1], args[2], args[3], args[4]);}
+        public int method4(int[] args) {return DragOver(args[0], args[1], args[2], args[3]);}
+        public int method5(int[] args) {return DragLeave();}
+        public int method6(int[] args) {return Drop(args[0], args[1], args[2], args[3], args[4]);}
+    };
+
+}
+
+void disposeCOMInterfaces() {
+    if (iDropTarget !is null)
+        iDropTarget.dispose();
+    iDropTarget = null;
+}
+
+int DragEnter(int pDataObject, int grfKeyState, int pt_x, int pt_y, int pdwEffect) {
+    selectedDataType = null;
+    selectedOperation = DND.DROP_NONE;
+    if (iDataObject !is null) iDataObject.Release();
+    iDataObject = null;
+
+    DNDEvent event = new DNDEvent();
+    if (!setEventData(event, pDataObject, grfKeyState, pt_x, pt_y, pdwEffect)) {
+        OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+        return COM.S_FALSE;
+    }
+
+    // Remember the iDataObject because it is not passed into the DragOver callback
+    iDataObject = new IDataObject(pDataObject);
+    iDataObject.AddRef();
+
+    int allowedOperations = event.operations;
+    TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+    System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+    notifyListeners(DND.DragEnter, event);
+    refresh();
+    if (event.detail is DND.DROP_DEFAULT) {
+        event.detail = (allowedOperations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+    }
+
+    selectedDataType = null;
+    for (int i = 0; i < allowedDataTypes.length; i++) {
+        if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
+            selectedDataType = allowedDataTypes[i];
+            break;
+        }
+    }
+
+    selectedOperation = DND.DROP_NONE;
+    if (selectedDataType !is null && ((allowedOperations & event.detail) !is 0)) {
+        selectedOperation = event.detail;
+    }
+
+    OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
+    return COM.S_OK;
+}
+
+int DragLeave() {
+    keyOperation = -1;
+
+    if (iDataObject is null) return COM.S_FALSE;
+
+    DNDEvent event = new DNDEvent();
+    event.widget = this;
+    event.time = OS.GetMessageTime();
+    event.detail = DND.DROP_NONE;
+    notifyListeners(DND.DragLeave, event);
+    refresh();
+
+    iDataObject.Release();
+    iDataObject = null;
+    return COM.S_OK;
+}
+
+int DragOver(int grfKeyState, int pt_x, int pt_y, int pdwEffect) {
+    if (iDataObject is null) return COM.S_FALSE;
+    int oldKeyOperation = keyOperation;
+
+    DNDEvent event = new DNDEvent();
+    if (!setEventData(event, iDataObject.getAddress(), grfKeyState, pt_x, pt_y, pdwEffect)) {
+        keyOperation = -1;
+        OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+        return COM.S_FALSE;
+    }
+
+    int allowedOperations = event.operations;
+    TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+    System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+
+    if (keyOperation is oldKeyOperation) {
+        event.type = DND.DragOver;
+        event.dataType = selectedDataType;
+        event.detail = selectedOperation;
+    } else {
+        event.type = DND.DragOperationChanged;
+        event.dataType = selectedDataType;
+    }
+    notifyListeners(event.type, event);
+    refresh();
+    if (event.detail is DND.DROP_DEFAULT) {
+        event.detail = (allowedOperations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+    }
+
+    selectedDataType = null;
+    for (int i = 0; i < allowedDataTypes.length; i++) {
+        if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
+            selectedDataType = allowedDataTypes[i];
+            break;
+        }
+    }
+
+    selectedOperation = DND.DROP_NONE;
+    if (selectedDataType !is null && ((allowedOperations & event.detail) is event.detail)) {
+        selectedOperation = event.detail;
+    }
+
+    OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
+    return COM.S_OK;
+}
+
+int Drop(int pDataObject, int grfKeyState, int pt_x, int pt_y, int pdwEffect) {
+    DNDEvent event = new DNDEvent();
+    event.widget = this;
+    event.time = OS.GetMessageTime();
+    if (dropEffect !is null) {
+        event.item = dropEffect.getItem(pt_x, pt_y);
+    }
+    event.detail = DND.DROP_NONE;
+    notifyListeners(DND.DragLeave, event);
+    refresh();
+
+    event = new DNDEvent();
+    if (!setEventData(event, pDataObject, grfKeyState, pt_x, pt_y, pdwEffect)) {
+        keyOperation = -1;
+        OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+        return COM.S_FALSE;
+    }
+    keyOperation = -1;
+    int allowedOperations = event.operations;
+    TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+    System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+    event.dataType = selectedDataType;
+    event.detail = selectedOperation;
+    notifyListeners(DND.DropAccept,event);
+    refresh();
+
+    selectedDataType = null;
+    for (int i = 0; i < allowedDataTypes.length; i++) {
+        if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
+            selectedDataType = allowedDataTypes[i];
+            break;
+        }
+    }
+    selectedOperation = DND.DROP_NONE;
+    if (selectedDataType !is null && (allowedOperations & event.detail) is event.detail) {
+        selectedOperation = event.detail;
+    }
+
+    if (selectedOperation is DND.DROP_NONE){
+        OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+        return COM.S_OK;
+    }
+
+    // Get Data in a Java format
+    Object object = null;
+    for (int i = 0; i < transferAgents.length; i++){
+        Transfer transfer = transferAgents[i];
+        if (transfer !is null && transfer.isSupportedType(selectedDataType)){
+            object = transfer.nativeToJava(selectedDataType);
+            break;
+        }
+    }
+    if (object is null){
+        selectedOperation = DND.DROP_NONE;
+    }
+
+    event.detail = selectedOperation;
+    event.dataType = selectedDataType;
+    event.data = object;
+    OS.ImageList_DragShowNolock(false);
+    try {
+        notifyListeners(DND.Drop,event);
+    } finally {
+        OS.ImageList_DragShowNolock(true);
+    }
+    refresh();
+    selectedOperation = DND.DROP_NONE;
+    if ((allowedOperations & event.detail) is event.detail) {
+        selectedOperation = event.detail;
+    }
+    //notify source of action taken
+    OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
+    return COM.S_OK;
+}
+
+/**
+ * Returns the Control which is registered for this DropTarget.  This is the control over which the
+ * user positions the cursor to drop the data.
+ *
+ * @return the Control which is registered for this DropTarget
+ */
+public Control getControl () {
+    return control;
+}
+
+/**
+ * Returns the drop effect for this DropTarget.  This drop effect will be
+ * used during a drag and drop to display the drag under effect on the
+ * target widget.
+ *
+ * @return the drop effect that is registered for this DropTarget
+ *
+ * @since 3.3
+ */
+public DropTargetEffect getDropTargetEffect() {
+    return dropEffect;
+}
+
+int getOperationFromKeyState(int grfKeyState) {
+    bool ctrl = (grfKeyState & OS.MK_CONTROL) !is 0;
+    bool shift = (grfKeyState & OS.MK_SHIFT) !is 0;
+    bool alt = (grfKeyState & OS.MK_ALT) !is 0;
+    if (alt) {
+        if (ctrl || shift) return DND.DROP_DEFAULT;
+        return DND.DROP_LINK;
+    }
+    if (ctrl && shift) return DND.DROP_LINK;
+    if (ctrl)return DND.DROP_COPY;
+    if (shift)return DND.DROP_MOVE;
+    return DND.DROP_DEFAULT;
+}
+
+/**
+ * Returns a list of the data types that can be transferred to this DropTarget.
+ *
+ * @return a list of the data types that can be transferred to this DropTarget
+ */
+public Transfer[] getTransfer() {
+    return transferAgents;
+}
+
+void onDispose () {
+    if (control is null) return;
+
+    COM.RevokeDragDrop(control.handle);
+
+    if (controlListener !is null)
+        control.removeListener(DWT.Dispose, controlListener);
+    controlListener = null;
+    control.setData(DROPTARGETID, null);
+    transferAgents = null;
+    control = null;
+
+    COM.CoLockObjectExternal(iDropTarget.getAddress(), false, true);
+
+    this.Release();
+
+    COM.CoFreeUnusedLibraries();
+}
+
+int opToOs(int operation) {
+    int osOperation = 0;
+    if ((operation & DND.DROP_COPY) !is 0){
+        osOperation |= COM.DROPEFFECT_COPY;
+    }
+    if ((operation & DND.DROP_LINK) !is 0) {
+        osOperation |= COM.DROPEFFECT_LINK;
+    }
+    if ((operation & DND.DROP_MOVE) !is 0) {
+        osOperation |= COM.DROPEFFECT_MOVE;
+    }
+    return osOperation;
+}
+
+int osToOp(int osOperation){
+    int operation = 0;
+    if ((osOperation & COM.DROPEFFECT_COPY) !is 0){
+        operation |= DND.DROP_COPY;
+    }
+    if ((osOperation & COM.DROPEFFECT_LINK) !is 0) {
+        operation |= DND.DROP_LINK;
+    }
+    if ((osOperation & COM.DROPEFFECT_MOVE) !is 0) {
+        operation |= DND.DROP_MOVE;
+    }
+    return operation;
+}
+
+/* QueryInterface([in] iid, [out] ppvObject)
+ * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
+ * must be incremented before returning.  Caller is responsible for releasing ppvObject.
+ */
+int QueryInterface(int riid, int ppvObject) {
+
+    if (riid is 0 || ppvObject is 0)
+        return COM.E_INVALIDARG;
+    GUID guid = new GUID();
+    COM.MoveMemory(guid, riid, GUID.sizeof);
+    if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDropTarget)) {
+        OS.MoveMemory(ppvObject, new int[] {iDropTarget.getAddress()}, 4);
+        AddRef();
+        return COM.S_OK;
+    }
+
+    OS.MoveMemory(ppvObject, new int[] {0}, 4);
+    return COM.E_NOINTERFACE;
+}
+
+int Release() {
+    refCount--;
+
+    if (refCount is 0) {
+        disposeCOMInterfaces();
+        COM.CoFreeUnusedLibraries();
+    }
+
+    return refCount;
+}
+
+void refresh() {
+    if (control is null || control.isDisposed()) return;
+    int handle = control.handle;
+    RECT lpRect = new RECT();
+    if (OS.GetUpdateRect(handle, lpRect, false)) {
+        OS.ImageList_DragShowNolock(false);
+        OS.RedrawWindow(handle, lpRect, 0, OS.RDW_UPDATENOW | OS.RDW_INVALIDATE);
+        OS.ImageList_DragShowNolock(true);
+    }
+}
+
+/**
+ * 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 be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DropTargetListener
+ * @see #addDropListener
+ */
+public void removeDropListener(DropTargetListener listener) {
+    if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT);
+    removeListener (DND.DragEnter, listener);
+    removeListener (DND.DragLeave, listener);
+    removeListener (DND.DragOver, listener);
+    removeListener (DND.DragOperationChanged, listener);
+    removeListener (DND.Drop, listener);
+    removeListener (DND.DropAccept, listener);
+}
+
+/**
+ * Specifies the drop effect for this DropTarget.  This drop effect will be
+ * used during a drag and drop to display the drag under effect on the
+ * target widget.
+ *
+ * @param effect the drop effect that is registered for this DropTarget
+ *
+ * @since 3.3
+ */
+public void setDropTargetEffect(DropTargetEffect effect) {
+    dropEffect = effect;
+}
+
+bool setEventData(DNDEvent event, int pDataObject, int grfKeyState, int pt_x, int pt_y, int pdwEffect) {
+    if (pDataObject is 0 || pdwEffect is 0) return false;
+
+    // get allowed operations
+    int style = getStyle();
+    int[] operations = new int[1];
+    OS.MoveMemory(operations, pdwEffect, 4);
+    operations[0] = osToOp(operations[0]) & style;
+    if (operations[0] is DND.DROP_NONE) return false;
+
+    // get current operation
+    int operation = getOperationFromKeyState(grfKeyState);
+    keyOperation = operation;
+    if (operation is DND.DROP_DEFAULT) {
+        if ((style & DND.DROP_DEFAULT) is 0) {
+            operation = (operations[0] & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+        }
+    } else {
+        if ((operation & operations[0]) is 0) operation = DND.DROP_NONE;
+    }
+
+    // Get allowed transfer types
+    TransferData[] dataTypes = new TransferData[0];
+    IDataObject dataObject = new IDataObject(pDataObject);
+    dataObject.AddRef();
+    try {
+        int[] address = new int[1];
+        if (dataObject.EnumFormatEtc(COM.DATADIR_GET, address) !is COM.S_OK) {
+            return false;
+        }
+        IEnumFORMATETC enumFormatetc = new IEnumFORMATETC(address[0]);
+        try {
+            // Loop over enumerator and save any types that match what we are looking for
+            int rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof);
+            try {
+                int[] pceltFetched = new int[1];
+                enumFormatetc.Reset();
+                while (enumFormatetc.Next(1, rgelt, pceltFetched) is COM.S_OK && pceltFetched[0] is 1) {
+                    TransferData transferData = new TransferData();
+                    transferData.formatetc = new FORMATETC();
+                    COM.MoveMemory(transferData.formatetc, rgelt, FORMATETC.sizeof);
+                    transferData.type = transferData.formatetc.cfFormat;
+                    transferData.pIDataObject = pDataObject;
+                    for (int i = 0; i < transferAgents.length; i++){
+                        Transfer transfer = transferAgents[i];
+                        if (transfer !is null && transfer.isSupportedType(transferData)){
+                            TransferData[] newDataTypes = new TransferData[dataTypes.length + 1];
+                            System.arraycopy(dataTypes, 0, newDataTypes, 0, dataTypes.length);
+                            newDataTypes[dataTypes.length] = transferData;
+                            dataTypes = newDataTypes;
+                            break;
+                        }
+                    }
+                }
+            } finally {
+                OS.GlobalFree(rgelt);
+            }
+        } finally {
+            enumFormatetc.Release();
+        }
+    } finally {
+        dataObject.Release();
+    }
+    if (dataTypes.length is 0) return false;
+
+    event.widget = this;
+    event.x = pt_x;
+    event.y = pt_y;
+    event.time = OS.GetMessageTime();
+    event.feedback = DND.FEEDBACK_SELECT;
+    event.dataTypes = dataTypes;
+    event.dataType = dataTypes[0];
+    if (dropEffect !is null) {
+        event.item = dropEffect.getItem(pt_x, pt_y);
+    }
+    event.operations = operations[0];
+    event.detail = operation;
+    return true;
+}
+
+/**
+ * Specifies the data types that can be transferred to this DropTarget.  If data is
+ * being dragged that does not match one of these types, the drop target will be notified of
+ * the drag and drop operation but the currentDataType will be null and the operation
+ * will be DND.NONE.
+ *
+ * @param transferAgents a list of Transfer objects which define the types of data that can be
+ *                       dropped on this target
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if transferAgents is null</li>
+ * </ul>
+ */
+public void setTransfer(Transfer[] transferAgents){
+    if (transferAgents is null) DND.error(DWT.ERROR_NULL_ARGUMENT);
+    this.transferAgents = transferAgents;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DropTargetAdapter.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DropTargetAdapter;
+
+import dwt.dnd.DropTargetListener;
+import dwt.dnd.DropTargetEvent;
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the <code>DropTargetListener</code> interface.
+ * <p>
+ * Classes that wish to deal with <code>DropTargetEvent</code>s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * </p>
+ *
+ * @see DropTargetListener
+ * @see DropTargetEvent
+ */
+public class DropTargetAdapter : DropTargetListener {
+
+/**
+ * This implementation of <code>dragEnter</code> permits the default
+ * operation defined in <code>event.detail</code>to be performed on the current data type
+ * defined in <code>event.currentDataType</code>.
+ * For additional information see <code>DropTargetListener.dragEnter</code>.
+ */
+public void dragEnter(DropTargetEvent event){}
+/**
+ * This implementation of <code>dragLeave</code> does nothing.
+ * For additional information see <code>DropTargetListener.dragOperationChanged</code>.
+ */
+public void dragLeave(DropTargetEvent event){}
+/**
+ * This implementation of <code>dragOperationChanged</code> permits the default
+ * operation defined in <code>event.detail</code>to be performed on the current data type
+ * defined in <code>event.currentDataType</code>.
+ * For additional information see <code>DropTargetListener.dragOperationChanged</code>.
+ */
+public void dragOperationChanged(DropTargetEvent event){}
+/**
+ * This implementation of <code>dragOver</code> permits the default
+ * operation defined in <code>event.detail</code>to be performed on the current data type
+ * defined in <code>event.currentDataType</code>.
+ * For additional information see <code>DropTargetListener.dragOver</code>.
+ */
+public void dragOver(DropTargetEvent event){}
+/**
+ * This implementation of <code>drop</code> does nothing.
+ * For additional information see <code>DropTargetListener.drop</code>.
+ */
+public void drop(DropTargetEvent event){}
+/**
+ * This implementation of <code>dropAccept</code> permits the default
+ * operation defined in <code>event.detail</code>to be performed on the current data type
+ * defined in <code>event.currentDataType</code>.
+ * For additional information see <code>DropTargetListener.dropAccept</code>.
+ */
+public void dropAccept(DropTargetEvent event){}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DropTargetEffect.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DropTargetEffect;
+
+
+import dwt.DWT;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Control;
+import dwt.widgets.Item;
+import dwt.widgets.Table;
+import dwt.widgets.Tree;
+import dwt.widgets.TreeItem;
+import dwt.widgets.Widget;
+import dwt.dnd.DropTargetAdapter;
+
+
+/**
+ * This class provides a default drag under effect during a drag and drop.
+ * The current implementation does not provide any visual feedback.
+ *
+ * <p>The drop target effect has the same API as the
+ * <code>DropTargetAdapter</code> so that it can provide custom visual
+ * feedback when a <code>DropTargetEvent</code> occurs.
+ * </p>
+ *
+ * <p>Classes that wish to provide their own drag under effect
+ * can extend the <code>DropTargetEffect</code> and override any applicable methods
+ * in <code>DropTargetAdapter</code> to display their own drag under effect.</p>
+ *
+ * <p>The feedback value is either one of the FEEDBACK constants defined in
+ * class <code>DND</code> which is applicable to instances of this class,
+ * or it must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> effect constants.
+ * </p>
+ * <p>
+ * <dl>
+ * <dt><b>Feedback:</b></dt>
+ * <dd>FEEDBACK_EXPAND, FEEDBACK_INSERT_AFTER, FEEDBACK_INSERT_BEFORE,
+ * FEEDBACK_NONE, FEEDBACK_SELECT, FEEDBACK_SCROLL</dd>
+ * </dl>
+ * </p>
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ *
+ * @since 3.3
+ */
+public class DropTargetEffect : DropTargetAdapter {
+    Control control;
+
+    /**
+     * Creates a new <code>DropTargetEffect</code> to handle the drag under effect on the specified
+     * <code>Control</code>.
+     *
+     * @param control the <code>Control</code> over which the user positions the cursor to drop the data
+     *
+     * @exception IllegalArgumentException <ul>
+     *    <li>ERROR_NULL_ARGUMENT - if the control is null</li>
+     * </ul>
+     */
+    public this(Control control) {
+        if (control is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+        this.control = control;
+    }
+
+    /**
+     * Returns the Control which is registered for this DropTargetEffect.  This is the control over which the
+     * user positions the cursor to drop the data.
+     *
+     * @return the Control which is registered for this DropTargetEffect
+     */
+    public Control getControl() {
+        return control;
+    }
+
+    /**
+     * Returns the item at the given x-y coordinate in the receiver
+     * or null if no such item exists. The x-y coordinate is in the
+     * display relative coordinates.
+     *
+     * @param x the x coordinate used to locate the item
+     * @param y the y coordinate used to locate the item
+     * @return the item at the given x-y coordinate, or null if the coordinate is not in a selectable item
+     */
+    public Widget getItem(int x, int y) {
+        if ( auto table = cast(Table)control ) {
+            return getItem(table, x, y);
+        }
+        if ( auto tree = cast(Tree)control ) {
+            return getItem(tree, x, y);
+        }
+        return null;
+    }
+
+    Widget getItem(Table table, int x, int y) {
+        Point coordinates = new Point(x, y);
+        coordinates = table.toControl(coordinates);
+        Item item = table.getItem(coordinates);
+        if (item is null) {
+            Rectangle area = table.getClientArea();
+            if (area.contains(coordinates)) {
+                // Scan across the width of the table.
+                for (int x1 = area.x; x1 < area.x + area.width; x1++) {
+                    Point pt = new Point(x1, coordinates.y);
+                    item = table.getItem(pt);
+                    if (item !is null) {
+                        break;
+                    }
+                }
+            }
+        }
+        return item;
+    }
+
+    Widget getItem(Tree tree, int x, int y) {
+        Point coordinates = new Point(x, y);
+        coordinates = tree.toControl(coordinates);
+        Item item = tree.getItem(coordinates);
+        if (item is null) {
+            Rectangle area = tree.getClientArea();
+            if (area.contains(coordinates)) {
+                // Scan across the width of the tree.
+                for (int x1 = area.x; x1 < area.x + area.width; x1++) {
+                    Point pt = new Point(x1, coordinates.y);
+                    item = tree.getItem(pt);
+                    if (item !is null) {
+                        break;
+                    }
+                }
+            }
+        }
+        return item;
+    }
+
+    TreeItem nextItem(Tree tree, TreeItem item) {
+        if (item is null) return null;
+        if (item.getExpanded()) return item.getItem(0);
+        TreeItem childItem = item;
+        TreeItem parentItem = childItem.getParentItem();
+        int index = parentItem is null ? tree.indexOf(childItem) : parentItem.indexOf(childItem);
+        int count = parentItem is null ? tree.getItemCount() : parentItem.getItemCount();
+        while (true) {
+            if (index + 1 < count) return parentItem is null ? tree.getItem(index + 1) : parentItem.getItem(index + 1);
+            if (parentItem is null) return null;
+            childItem = parentItem;
+            parentItem = childItem.getParentItem();
+            index = parentItem is null ? tree.indexOf(childItem) : parentItem.indexOf(childItem);
+            count = parentItem is null ? tree.getItemCount() : parentItem.getItemCount();
+        }
+    }
+
+    TreeItem previousItem(Tree tree, TreeItem item) {
+        if (item is null) return null;
+        TreeItem childItem = item;
+        TreeItem parentItem = childItem.getParentItem();
+        int index = parentItem is null ? tree.indexOf(childItem) : parentItem.indexOf(childItem);
+        if (index is 0) return parentItem;
+        TreeItem nextItem = parentItem is null ? tree.getItem(index-1) : parentItem.getItem(index-1);
+        int count = nextItem.getItemCount();
+        while (count > 0 && nextItem.getExpanded()) {
+            nextItem = nextItem.getItem(count - 1);
+            count = nextItem.getItemCount();
+        }
+        return nextItem;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DropTargetEvent.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DropTargetEvent;
+
+
+import dwt.events.TypedEvent;
+import dwt.widgets.Widget;
+import dwt.dnd.TransferData;
+import dwt.dnd.DNDEvent;
+import dwt.widgets.Event;
+
+/**
+ * The DropTargetEvent contains the event information passed in the methods of the DropTargetListener.
+ */
+public class DropTargetEvent : TypedEvent {
+    /**
+     * The x-cordinate of the cursor relative to the <code>Display</code>
+     */
+    public int x;
+
+    /**
+     * The y-cordinate of the cursor relative to the <code>Display</code>
+     */
+    public int y;
+
+    /**
+     * The operation being performed.
+     * @see DND#DROP_NONE
+     * @see DND#DROP_MOVE
+     * @see DND#DROP_COPY
+     * @see DND#DROP_LINK
+     */
+    public int detail;
+
+    /**
+     * A bitwise OR'ing of the operations that the DragSource can support
+     * (e.g. DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK).
+     * The detail value must be a member of this list or DND.DROP_NONE.
+     * @see DND#DROP_NONE
+     * @see DND#DROP_MOVE
+     * @see DND#DROP_COPY
+     * @see DND#DROP_LINK
+     */
+    public int operations;
+
+    /**
+     * A bitwise OR'ing of the drag under effect feedback to be displayed to the user
+     * (e.g. DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL | DND.FEEDBACK_EXPAND).
+     * <p>A value of DND.FEEDBACK_NONE indicates that no drag under effect will be displayed.</p>
+     * <p>Feedback effects will only be applied if they are applicable.</p>
+     * <p>The default value is DND.FEEDBACK_SELECT.</p>
+     * @see DND#FEEDBACK_NONE
+     * @see DND#FEEDBACK_SELECT
+     * @see DND#FEEDBACK_INSERT_BEFORE
+     * @see DND#FEEDBACK_INSERT_AFTER
+     * @see DND#FEEDBACK_SCROLL
+     * @see DND#FEEDBACK_EXPAND
+     */
+    public int feedback;
+
+    /**
+     * If the associated control is a table or tree, this field contains the item located
+     * at the cursor coordinates.
+     */
+    public Widget item;
+
+    /**
+     * The type of data that will be dropped.
+     */
+    public TransferData currentDataType;
+
+    /**
+     * A list of the types of data that the DragSource is capable of providing.
+     * The currentDataType must be a member of this list.
+     */
+    public TransferData[] dataTypes;
+
+    static const long serialVersionUID = 3256727264573338678L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public this(DNDEvent e) {
+    super(cast(Event)e);
+    this.data = e.data;
+    this.x = e.x;
+    this.y = e.y;
+    this.detail = e.detail;
+    this.currentDataType = e.dataType;
+    this.dataTypes = e.dataTypes;
+    this.operations = e.operations;
+    this.feedback = e.feedback;
+    this.item = e.item;
+}
+void updateEvent(DNDEvent e) {
+    e.widget = this.widget;
+    e.time = this.time;
+    e.data = this.data;
+    e.x = this.x;
+    e.y = this.y;
+    e.detail = this.detail;
+    e.dataType = this.currentDataType;
+    e.dataTypes = this.dataTypes;
+    e.operations = this.operations;
+    e.feedback = this.feedback;
+    e.item = this.item;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DropTargetListener.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,253 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.DropTargetListener;
+
+import dwt.internal.DWTEventListener;
+import dwt.dnd.DropTargetEvent;
+
+/**
+ * The <code>DropTargetListener</code> class provides event notification to the application
+ * for DropTarget events.
+ *
+ * <p>As the user moves the cursor into, over and out of a Control that has been designated
+ * as a DropTarget, events indicate what operation can be performed and what data can be
+ * transferred if a drop where to occur at that point.
+ * The application can respond to these events and change the type of data that will
+ * be dropped by modifying event.currentDataType, or change the operation that will be performed
+ * by modifying the event.detail field or stop any drop from happening on the current target
+ * by setting the event.detail field to DND_DROP_NONE.</p>
+ *
+ * <p>When the user causes a drop to happen by releasing the mouse over a valid drop target,
+ * the application has one last chance to change the data type of the drop through the
+ * DropAccept event.  If the drop is still allowed, the DropAccept event is immediately
+ * followed by the Drop event.  In the Drop event, the application can still change the
+ * operation that is performed but the data type is fixed.</p>
+ *
+ * @see DropTargetEvent
+ *
+ */
+public interface DropTargetListener : DWTEventListener {
+
+/**
+ * The cursor has entered the drop target boundaries.
+ *
+ * <p>The following fields in the DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in)dataTypes
+ * <li>(in,out)currentDataType
+ * <li>(in)operations
+ * <li>(in,out)detail
+ * <li>(in,out)feedback
+ * </ul></p>
+ *
+ * <p>The <code>operation</code> value is determined by the modifier keys pressed by the user.
+ * If no keys are pressed the <code>event.detail</code> field is set to DND.DROP_DEFAULT.
+ * If the application does not set the <code>event.detail</code> to something other
+ * than <code>DND.DROP_DEFAULT</code> the operation will be set to the platform defined standard
+ * default.</p>
+ *
+ * <p>The <code>currentDataType</code> is determined by the first transfer agent specified in
+ * setTransfer() that matches a data type provided by the drag source.</p>
+ *
+ * <p>It is possible to get a DragEnter event when the drag source does not provide any matching data.
+ * In this case, the default operation is DND.DROP_NONE and the currentDataType is null.</p>
+ *
+ * <p>The application can change the operation that will be performed by modifying the
+ * <code>detail</code> field but the choice must be one of the values in the <code>operations</code>
+ * field or DND.DROP_NONE.</p>
+ *
+ * <p>The application can also change the type of data being requested by
+ * modifying the <code>currentDataTypes</code> field  but the value must be one of the values
+ * in the <code>dataTypes</code> list.</p>
+ *
+ * @param event  the information associated with the drag enter event
+ *
+ * @see DropTargetEvent
+ */
+public void dragEnter(DropTargetEvent event);
+
+/**
+ * The cursor has left the drop target boundaries OR the drop has been cancelled OR the data
+ * is about to be dropped.
+ *
+ * <p>The following fields in the DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in)dataTypes
+ * <li>(in)currentDataType
+ * <li>(in)operations
+ * <li>(in)detail
+ * </ul></p>
+ *
+ * @param event  the information associated with the drag leave event
+ *
+ * @see DropTargetEvent
+ */
+public void dragLeave(DropTargetEvent event);
+
+/**
+ * The operation being performed has changed (usually due to the user changing the selected modifier key(s)
+ * while dragging).
+ *
+ * <p>The following fields in the DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in)dataTypes
+ * <li>(in,out)currentDataType
+ * <li>(in)operations
+ * <li>(in,out)detail
+ * <li>(in,out)feedback
+ * </ul></p>
+ *
+ * <p>The <code>operation</code> value is determined by the modifier keys pressed by the user.
+ * If no keys are pressed the <code>event.detail</code> field is set to DND.DROP_DEFAULT.
+ * If the application does not set the <code>event.detail</code> to something other than
+ * <code>DND.DROP_DEFAULT</code> the operation will be set to the platform defined standard default.</p>
+ *
+ * <p>The <code>currentDataType</code> value is determined by the value assigned to
+ * <code>currentDataType</code> in previous dragEnter and dragOver calls.</p>
+ *
+ * <p>The application can change the operation that will be performed by modifying the
+ * <code>detail</code> field but the choice must be one of the values in the <code>operations</code>
+ * field.</p>
+ *
+ * <p>The application can also change the type of data being requested by modifying
+ * the <code>currentDataTypes</code> field  but the value must be one of the values in the
+ * <code>dataTypes</code> list.</p>
+ *
+ * @param event  the information associated with the drag operation changed event
+ *
+ * @see DropTargetEvent
+ */
+public void dragOperationChanged(DropTargetEvent event);
+
+/**
+ * The cursor is moving over the drop target.
+ *
+ * <p>The following fields in the DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in)dataTypes
+ * <li>(in,out)currentDataType
+ * <li>(in)operations
+ * <li>(in,out)detail
+ * <li>(in,out)feedback
+ * </ul></p>
+ *
+ * <p>The <code>operation</code> value is determined by the value assigned to
+ * <code>currentDataType</code> in previous dragEnter and dragOver calls.</p>
+ *
+ * <p>The <code>currentDataType</code> value is determined by the value assigned to
+ * <code>currentDataType</code> in previous dragEnter and dragOver calls.</p>
+ *
+ * <p>The application can change the operation that will be performed by modifying the
+ * <code>detail</code> field but the choice must be one of the values in the <code>operations</code>
+ * field.</p>
+ *
+ * <p>The application can also change the type of data being requested by modifying the
+ * <code>currentDataTypes</code> field  but the value must be one of the values in the
+ * <code>dataTypes</code> list.</p>
+ *
+ * <p>NOTE: At this point the <code>data</code> field is null.  On some platforms, it is possible
+ * to obtain the data being transferred before the transfer occurs but in most platforms this is
+ * not possible.  On those platforms where the data is available, the application can access the
+ * data as follows:</p>
+ *
+ * <pre><code>
+ * public void dragOver(DropTargetEvent event) {
+ *       TextTransfer textTransfer = TextTransfer.getInstance();
+ *       String data = (String)textTransfer.nativeToJava(event.currentDataType);
+ *       if (data !is null) {
+ *           System.out.println("Data to be dropped is (Text)"+data);
+ *       }
+ * };
+ * </code></pre>
+ *
+ * @param event  the information associated with the drag over event
+ *
+ * @see DropTargetEvent
+ */
+public void dragOver(DropTargetEvent event);
+
+/**
+ * The data is being dropped.  The data field contains java format of the data being dropped.
+ * To determine the type of the data object, refer to the documentation for the Transfer subclass
+ * specified in event.currentDataType.
+ *
+ * <p>The following fields in DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in,out)detail
+ * <li>(in)currentDataType
+ * <li>(in)data
+ * </ul></p>
+ *
+ * <p>The application can refuse to perform the drop operation by setting the detail
+ * field to DND.DROP_NONE.</p>
+ *
+ * @param event the information associated with the drop event
+ *
+ * @see DropTargetEvent
+ */
+public void drop(DropTargetEvent event);
+
+/**
+ * The drop is about to be performed.
+ * The drop target is given a last chance to change the nature of the drop.
+ *
+ * <p>The following fields in the DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in)dataTypes
+ * <li>(in,out)currentDataType
+ * <li>(in)operations
+ * <li>(in,out)detail
+ * </ul></p>
+ *
+ * <p>The application can veto the drop by setting the <code>event.detail</code> field to
+ * <code>DND.DROP_NONE</code>.</p>
+ *
+ * <p>The application can change the operation that will be performed by modifying the
+ * <code>detail</code> field but the choice must be one of the values in the
+ * <code>operations</code> field.</p>
+ *
+ * <p>The application can also change the type of data being requested by modifying the
+ * <code>currentDataTypes</code> field  but the value must be one of the values in the <
+ * code>dataTypes</code> list.</p>
+ *
+ * @param event  the information associated with the drop accept event
+ *
+ * @see DropTargetEvent
+ */
+public void dropAccept(DropTargetEvent event);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/FileTransfer.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.FileTransfer;
+
+import dwt.internal.ole.win32.COM;
+import dwt.internal.win32.OS;
+
+
+/**
+ * The class <code>FileTransfer</code> provides a platform specific mechanism
+ * for converting a list of files represented as a java <code>String[]</code> to a
+ * platform specific representation of the data and vice versa.
+ * Each <code>String</code> in the array contains the absolute path for a single
+ * file or directory.
+ * See <code>Transfer</code> for additional information.
+ *
+ * <p>An example of a java <code>String[]</code> containing a list of files is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     File file1 = new File("C:\temp\file1");
+ *     File file2 = new File("C:\temp\file2");
+ *     String[] fileData = new String[2];
+ *     fileData[0] = file1.getAbsolutePath();
+ *     fileData[1] = file2.getAbsolutePath();
+ * </code></pre>
+ */
+public class FileTransfer : ByteArrayTransfer {
+
+    private static FileTransfer _instance = new FileTransfer();
+    private static final String CF_HDROP = "CF_HDROP "; //$NON-NLS-1$
+    private static final int CF_HDROPID = COM.CF_HDROP;
+    private static final String CF_HDROP_SEPARATOR = "\0"; //$NON-NLS-1$
+
+private this() {}
+
+/**
+ * Returns the singleton instance of the FileTransfer class.
+ *
+ * @return the singleton instance of the FileTransfer class
+ */
+public static FileTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * 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 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;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of a list of file names to a java <code>String[]</code>.
+ * Each String in the array contains the absolute path for a single file or directory.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>String[]</code> containing a list of file names if the
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData) {
+    if (!isSupportedType(transferData) || transferData.pIDataObject is 0)  return null;
+
+    // get file names from IDataObject
+    IDataObject dataObject = new IDataObject(transferData.pIDataObject);
+    dataObject.AddRef();
+    FORMATETC formatetc = new FORMATETC();
+    formatetc.cfFormat = COM.CF_HDROP;
+    formatetc.ptd = 0;
+    formatetc.dwAspect = COM.DVASPECT_CONTENT;
+    formatetc.lindex = -1;
+    formatetc.tymed = COM.TYMED_HGLOBAL;
+    STGMEDIUM stgmedium = new STGMEDIUM();
+    stgmedium.tymed = COM.TYMED_HGLOBAL;
+    transferData.result = dataObject.GetData(formatetc, stgmedium);
+    dataObject.Release();
+    if (transferData.result !is COM.S_OK) return null;
+    // How many files are there?
+    int count = OS.DragQueryFile(stgmedium.unionField, 0xFFFFFFFF, null, 0);
+    String[] fileNames = new String[count];
+    for (int i = 0; i < count; i++) {
+        // How long is the name ?
+        int size = OS.DragQueryFile(stgmedium.unionField, i, null, 0) + 1;
+        TCHAR lpszFile = new TCHAR(0, size);
+        // Get file name and append it to string
+        OS.DragQueryFile(stgmedium.unionField, i, lpszFile, size);
+        fileNames[i] = lpszFile.toString(0, lpszFile.strlen());
+    }
+    OS.DragFinish(stgmedium.unionField); // frees data associated with HDROP data
+    return fileNames;
+}
+
+protected int[] getTypeIds(){
+    return new int[] {CF_HDROPID};
+}
+
+protected String[] getTypeNames(){
+    return new String[] {CF_HDROP};
+}
+bool checkFile(Object object) {
+    if (object is null || !(object instanceof String[]) || ((String[])object).length is 0) return false;
+    String[] strings = (String[])object;
+    for (int i = 0; i < strings.length; i++) {
+        if (strings[i] is null || strings[i].length() is 0) return false;
+    }
+    return true;
+}
+
+protected bool validate(Object object) {
+    return checkFile(object);
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/HTMLTransfer.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.HTMLTransfer;
+
+import dwt.internal.ole.win32.COM;
+import dwt.internal.win32.OS;
+
+/**
+ * The class <code>HTMLTransfer</code> provides a platform specific mechanism
+ * for converting text in HTML format represented as a java <code>String</code>
+ * to a platform specific representation of the data and vice versa.  See
+ * <code>Transfer</code> for additional information.
+ *
+ * <p>An example of a java <code>String</code> containing HTML text is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     String htmlData = "<p>This is a paragraph of text.</p>";
+ * </code></pre>
+ */
+public class HTMLTransfer : ByteArrayTransfer {
+
+    static HTMLTransfer _instance = new HTMLTransfer();
+    static final String HTML_FORMAT = "HTML Format"; //$NON-NLS-1$
+    static final int HTML_FORMATID = registerType(HTML_FORMAT);
+    static final String NUMBER = "00000000"; //$NON-NLS-1$
+    static final String HEADER = "Version:0.9\r\nStartHTML:"+NUMBER+"\r\nEndHTML:"+NUMBER+"\r\nStartFragment:"+NUMBER+"\r\nEndFragment:"+NUMBER+"\r\n";
+    static final String PREFIX = "<html><body><!--StartFragment-->"; //$NON-NLS-1$
+    static final String SUFFIX = "<!--EndFragment--></body></html>"; //$NON-NLS-1$
+    static final String StartFragment = "StartFragment:"; //$NON-NLS-1$
+    static final String EndFragment = "EndFragment:"; //$NON-NLS-1$
+
+private this() {}
+
+/**
+ * Returns the singleton instance of the HTMLTransfer class.
+ *
+ * @return the singleton instance of the HTMLTransfer class
+ */
+public static HTMLTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts HTML-formatted text
+ * represented by a java <code>String</code> to a platform specific representation.
+ * For additional information see <code>Transfer#javaToNative</code>.
+ *
+ * @param object a java <code>String</code> containing HTML text
+ * @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 (!checkHTML(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    String string = (String)object;
+    int count = string.length();
+    char[] chars = new char[count + 1];
+    string.getChars(0, count, chars, 0);
+    int codePage = OS.GetACP();
+    int cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+    if (cchMultiByte is 0) {
+        transferData.stgmedium = new STGMEDIUM();
+        transferData.result = COM.DV_E_STGMEDIUM;
+        return;
+    }
+    int startHTML = HEADER.length();
+    int startFragment = startHTML + PREFIX.length();
+    int endFragment = startFragment + cchMultiByte - 1;
+    int endHTML = endFragment + SUFFIX.length();
+
+    StringBuffer buffer = new StringBuffer(HEADER);
+    int maxLength = NUMBER.length();
+    //startHTML
+    int start = buffer.toString().indexOf(NUMBER);
+    String temp = Integer.toString(startHTML);
+    buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+    //endHTML
+    start = buffer.toString().indexOf(NUMBER, start);
+    temp = Integer.toString(endHTML);
+    buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+    //startFragment
+    start = buffer.toString().indexOf(NUMBER, start);
+    temp = Integer.toString(startFragment);
+    buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+    //endFragment
+    start = buffer.toString().indexOf(NUMBER, start);
+    temp = Integer.toString(endFragment);
+    buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+
+    buffer.append(PREFIX);
+    buffer.append(string);
+    buffer.append(SUFFIX);
+
+    count = buffer.length();
+    chars = new char[count + 1];
+    buffer.getChars(0, count, chars, 0);
+    cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+    int lpMultiByteStr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, cchMultiByte);
+    OS.WideCharToMultiByte(codePage, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+    transferData.stgmedium = new STGMEDIUM();
+    transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+    transferData.stgmedium.unionField = lpMultiByteStr;
+    transferData.stgmedium.pUnkForRelease = 0;
+    transferData.result = COM.S_OK;
+    return;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of HTML text to a java <code>String</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>String</code> containing HTML text if the
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData){
+    if (!isSupportedType(transferData) || transferData.pIDataObject is 0) return null;
+    IDataObject data = new IDataObject(transferData.pIDataObject);
+    data.AddRef();
+    STGMEDIUM stgmedium = new STGMEDIUM();
+    FORMATETC formatetc = transferData.formatetc;
+    stgmedium.tymed = COM.TYMED_HGLOBAL;
+    transferData.result = data.GetData(formatetc, stgmedium);
+    data.Release();
+    if (transferData.result !is COM.S_OK) return null;
+    int hMem = stgmedium.unionField;
+
+    try {
+        int lpMultiByteStr = OS.GlobalLock(hMem);
+        if (lpMultiByteStr is 0) return null;
+        try {
+            int codePage = OS.GetACP();
+            int cchWideChar  = OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, null, 0);
+            if (cchWideChar is 0) return null;
+            char[] lpWideCharStr = new char [cchWideChar - 1];
+            OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, lpWideCharStr, lpWideCharStr.length);
+            String string = new String(lpWideCharStr);
+            int fragmentStart = 0, fragmentEnd = 0;
+            int start = string.indexOf(StartFragment) + StartFragment.length();
+            int end = start + 1;
+            while (end < string.length()) {
+                String s = string.substring(start, end);
+                try {
+                    fragmentStart = Integer.parseInt(s);
+                    end++;
+                } catch (NumberFormatException e) {
+                    break;
+                }
+            }
+            start = string.indexOf(EndFragment) + EndFragment.length();
+            end = start + 1;
+            while (end < string.length()) {
+                String s = string.substring(start, end);
+                try {
+                    fragmentEnd = Integer.parseInt(s);
+                    end++;
+                } catch (NumberFormatException e) {
+                    break;
+                }
+            }
+            if (fragmentEnd <= fragmentStart || fragmentEnd > lpWideCharStr.length) return null;
+            /* TO DO:
+             * FragmentStart and FragmentEnd are offsets in original byte stream, not
+             * the wide char version of the byte stream.
+             */
+            String s = string.substring(fragmentStart, fragmentEnd);
+            /*
+             * Firefox includes <!--StartFragment --> in the fragment, so remove it.
+             */
+            String foxStart = "<!--StartFragment -->\r\n"; //$NON-NLS-1$
+            int prefix = s.indexOf(foxStart);
+            if (prefix !is -1) {
+                prefix += foxStart.length();
+                s = s.substring(prefix);
+            }
+            return s;
+        } finally {
+            OS.GlobalUnlock(hMem);
+        }
+    } finally {
+        OS.GlobalFree(hMem);
+    }
+}
+protected int[] getTypeIds(){
+    return new int[] {HTML_FORMATID};
+}
+protected String[] getTypeNames(){
+    return new String[] {HTML_FORMAT};
+}
+bool checkHTML(Object object) {
+    return (object !is null && object instanceof String && ((String)object).length() > 0);
+}
+protected bool validate(Object object) {
+    return checkHTML(object);
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/OleEnumFORMATETC.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.OleEnumFORMATETC;
+
+import dwt.internal.ole.win32.COM;
+import dwt.internal.ole.win32.OBJIDL;
+import dwt.internal.ole.win32.extras;
+
+final class OleEnumFORMATETC {
+
+    private _IEnumFORMATETCImpl iEnumFORMATETC;
+
+    private int refCount;
+    private int index;
+
+    private FORMATETC*[] formats;
+
+this() {
+
+    createCOMInterfaces();
+
+}
+int AddRef() {
+    refCount++;
+    return refCount;
+}
+private void createCOMInterfaces() {
+    // register each of the interfaces that this object implements
+    iEnumFORMATETC = new _IEnumFORMATETCImpl( this );
+}
+private void disposeCOMInterfaces() {
+    iEnumFORMATETC = null;
+}
+IEnumFORMATETC getAddress() {
+    return iEnumFORMATETC;
+}
+private FORMATETC*[] getNextItems(int numItems){
+
+    if (formats is null || numItems < 1) return null;
+
+    int endIndex = index + numItems - 1;
+    if (endIndex > (formats.length - 1)) endIndex = formats.length - 1;
+    if (index > endIndex) return null;
+
+    FORMATETC*[] items =  new FORMATETC*[endIndex - index + 1];
+    for (int i = 0; i < items.length; i++){
+        items[i] = formats[index];
+        index++;
+    }
+
+    return items;
+}
+
+package HRESULT Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) {
+    /* Retrieves the next celt items in the enumeration sequence.
+       If there are fewer than the requested number of elements left in the sequence,
+       it retrieves the remaining elements.
+       The number of elements actually retrieved is returned through pceltFetched
+       (unless the caller passed in NULL for that parameter).
+    */
+
+    if (rgelt is null) return COM.E_INVALIDARG;
+    if (pceltFetched is null && celt !is 1) return COM.E_INVALIDARG;
+
+    FORMATETC*[] nextItems = getNextItems(celt);
+    if (nextItems !is null) {
+        for (int i = 0; i < nextItems.length; i++) {
+            rgelt[i] = nextItems[i];
+        }
+
+        if (pceltFetched !is 0)
+            *pceltFetched = nextItems.length;
+
+        if (nextItems.length is celt) return COM.S_OK;
+
+    } else {
+        if (pceltFetched !is 0)
+            *pceltFetched = 0;
+        COM.MoveMemory(rgelt, & FORMATETC.init, FORMATETC.sizeof);
+
+    }
+    return COM.S_FALSE;
+}
+private int QueryInterface(int riid, int ppvObject) {
+
+    if (riid is null || ppvObject is null) return COM.E_NOINTERFACE;
+
+    if (COM.IsEqualGUID(riid, &COM.IIDIUnknown)) {
+        *ppvObject = cast(void*)cast(IUnknown)iUnknown;
+        AddRef();
+        return COM.S_OK;
+    }
+    if (COM.IsEqualGUID(riid, &COM.IIDIEnumFORMATETC)) {
+        *ppvObject = cast(void*)cast(IEnumFORMATETC)iEnumFORMATETC;
+        AddRef();
+        return COM.S_OK;
+    }
+    *ppvObject = null;
+    return COM.E_NOINTERFACE;
+}
+int Release() {
+    refCount--;
+
+    if (refCount is 0) {
+        disposeCOMInterfaces();
+        COM.CoFreeUnusedLibraries();
+    }
+
+    return refCount;
+}
+private int Reset() {
+    //Resets the enumeration sequence to the beginning.
+    index = 0;
+    return COM.S_OK;
+}
+void setFormats(FORMATETC*[] newFormats) {
+    formats = newFormats;
+    index = 0;
+}
+private int Skip(int celt) {
+    //Skips over the next specified number of elements in the enumeration sequence.
+    if (celt < 1 ) return COM.E_INVALIDARG;
+
+    index += celt;
+    if (index > (formats.length - 1)){
+        index = formats.length - 1;
+        return COM.S_FALSE;
+    }
+    return COM.S_OK;
+}
+}
+
+class _IEnumFORMATETCImpl : IEnumFORMATETC {
+
+
+    OleEnumFORMATETC    parent;
+    this(OleEnumFORMATETC   p) { parent = p; }
+extern (Windows):
+    // interface of IUnknown
+    HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
+    ULONG AddRef()  { return parent.AddRef(); }
+    ULONG Release() { return parent.Release(); }
+
+    // interface of IEnumFORMATETC
+    HRESULT Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) {
+        return parent.Next(celt, rgelt, pceltFetched);
+    }
+    HRESULT Skip(ULONG celt) { return parent.Skip(celt); }
+    HRESULT Reset() { return parent.Reset(); }
+    HRESULT Clone(IEnumFORMATETC * ppenum) { return COM.E_NOTIMPL;}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/RTFTransfer.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.RTFTransfer;
+
+import dwt.internal.ole.win32.COM;
+import dwt.internal.win32.OS;
+
+/**
+ * The class <code>RTFTransfer</code> provides a platform specific mechanism
+ * for converting text in RTF format represented as a java <code>String</code>
+ * to a platform specific representation of the data and vice versa.  See
+ * <code>Transfer</code> for additional information.
+ *
+ * <p>An example of a java <code>String</code> containing RTF text is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     String rtfData = "{\\rtf1{\\colortbl;\\red255\\green0\\blue0;}\\uc1\\b\\i Hello World}";
+ * </code></pre>
+ */
+public class RTFTransfer : ByteArrayTransfer {
+
+    private static RTFTransfer _instance = new RTFTransfer();
+    private static final String CF_RTF = "Rich Text Format"; //$NON-NLS-1$
+    private static final int CF_RTFID = registerType(CF_RTF);
+
+private this() {}
+
+/**
+ * Returns the singleton instance of the RTFTransfer class.
+ *
+ * @return the singleton instance of the RTFTransfer class
+ */
+public static RTFTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts RTF-formatted text
+ * represented by a java <code>String</code> to a platform specific representation.
+ * For additional information see <code>Transfer#javaToNative</code>.
+ *
+ * @param object a java <code>String</code> containing RTF text
+ * @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 (!checkRTF(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    // CF_RTF is stored as a null terminated byte array
+    String string = (String)object;
+    int count = string.length();
+    char[] chars = new char[count + 1];
+    string.getChars(0, count, chars, 0);
+    int codePage = OS.GetACP();
+    int cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+    if (cchMultiByte is 0) {
+        transferData.stgmedium = new STGMEDIUM();
+        transferData.result = COM.DV_E_STGMEDIUM;
+        return;
+    }
+    int lpMultiByteStr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, cchMultiByte);
+    OS.WideCharToMultiByte(codePage, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+    transferData.stgmedium = new STGMEDIUM();
+    transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+    transferData.stgmedium.unionField = lpMultiByteStr;
+    transferData.stgmedium.pUnkForRelease = 0;
+    transferData.result = COM.S_OK;
+    return;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of RTF text to a java <code>String</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>String</code> containing RTF text if the
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData){
+    if (!isSupportedType(transferData) || transferData.pIDataObject is 0) return null;
+    IDataObject data = new IDataObject(transferData.pIDataObject);
+    data.AddRef();
+    STGMEDIUM stgmedium = new STGMEDIUM();
+    FORMATETC formatetc = transferData.formatetc;
+    stgmedium.tymed = COM.TYMED_HGLOBAL;
+    transferData.result = data.GetData(formatetc, stgmedium);
+    data.Release();
+    if (transferData.result !is COM.S_OK) return null;
+    int hMem = stgmedium.unionField;
+    try {
+        int lpMultiByteStr = OS.GlobalLock(hMem);
+        if (lpMultiByteStr is 0) return null;
+        try {
+            int codePage = OS.GetACP();
+            int cchWideChar  = OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, null, 0);
+            if (cchWideChar is 0) return null;
+            char[] lpWideCharStr = new char [cchWideChar - 1];
+            OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, lpWideCharStr, lpWideCharStr.length);
+            return new String(lpWideCharStr);
+        } finally {
+            OS.GlobalUnlock(hMem);
+        }
+    } finally {
+        OS.GlobalFree(hMem);
+    }
+}
+
+protected int[] getTypeIds(){
+    return new int[] {CF_RTFID};
+}
+
+protected String[] getTypeNames(){
+    return new String[] {CF_RTF};
+}
+
+bool checkRTF(Object object) {
+    return (object !is null  && object instanceof String && ((String)object).length() > 0);
+}
+
+protected bool validate(Object object) {
+    return checkRTF(object);
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TableDragSourceEffect.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.TableDragSourceEffect;
+
+import dwt.DWT;
+import dwt.graphics.Image;
+import dwt.graphics.Rectangle;
+import dwt.internal.win32.OS;
+import dwt.widgets.Display;
+import dwt.widgets.Table;
+import dwt.widgets.TableItem;
+
+/**
+ * This class provides default implementations to display a source image
+ * when a drag is initiated from a <code>Table</code>.
+ *
+ * <p>Classes that wish to provide their own source image for a <code>Table</code> can
+ * extend the <code>TableDragSourceEffect</code> class, override the
+ * <code>TableDragSourceEffect.dragStart</code> method and set the field
+ * <code>DragSourceEvent.image</code> with their own image.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag source effect implementation.
+ *
+ * @see DragSourceEffect
+ * @see DragSourceEvent
+ *
+ * @since 3.3
+ */
+public class TableDragSourceEffect : DragSourceEffect {
+    Image dragSourceImage = null;
+
+    /**
+     * Creates a new <code>TableDragSourceEffect</code> to handle drag effect
+     * from the specified <code>Table</code>.
+     *
+     * @param table the <code>Table</code> that the user clicks on to initiate the drag
+     */
+    public this(Table table) {
+        super(table);
+    }
+
+    /**
+     * This implementation of <code>dragFinished</code> disposes the image
+     * that was created in <code>TableDragSourceEffect.dragStart</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragFinished(event)</code>
+     * to dispose the image in the default implementation.
+     *
+     * @param event the information associated with the drag finished event
+     */
+    public void dragFinished(DragSourceEvent event) {
+        if (dragSourceImage !is null) dragSourceImage.dispose();
+        dragSourceImage = null;
+    }
+
+    /**
+     * This implementation of <code>dragStart</code> will create a default
+     * image that will be used during the drag. The image should be disposed
+     * when the drag is completed in the <code>TableDragSourceEffect.dragFinished</code>
+     * method.
+     *
+     * Subclasses that override this method should call <code>super.dragStart(event)</code>
+     * to use the image from the default implementation.
+     *
+     * @param event the information associated with the drag start event
+     */
+    public void dragStart(DragSourceEvent event) {
+        event.image = getDragSourceImage(event);
+    }
+
+    Image getDragSourceImage(DragSourceEvent event) {
+        if (dragSourceImage !is null) dragSourceImage.dispose();
+        dragSourceImage = null;
+        Table table = (Table) control;
+        TableItem[] selection = table.getSelection();
+        if (selection.length is 0) return null;
+        int tableImageList = OS.SendMessage (table.handle, OS.LVM_GETIMAGELIST, OS.LVSIL_SMALL, 0);
+        if (tableImageList !is 0) {
+            int count = Math.min(selection.length, 10);
+            Rectangle bounds = selection[0].getBounds(0);
+            for (int i = 1; i < count; i++) {
+                bounds = bounds.union(selection[i].getBounds(0));
+            }
+            int hDC = OS.GetDC(0);
+            int hDC1 = OS.CreateCompatibleDC(hDC);
+            int bitmap = OS.CreateCompatibleBitmap(hDC, bounds.width, bounds.height);
+            int hOldBitmap = OS.SelectObject(hDC1, bitmap);
+            RECT rect = new RECT();
+            rect.right = bounds.width;
+            rect.bottom = bounds.height;
+            int hBrush = OS.GetStockObject(OS.WHITE_BRUSH);
+            OS.FillRect(hDC1, rect, hBrush);
+            for (int i = 0; i < count; i++) {
+                TableItem selected = selection[i];
+                Rectangle cell = selected.getBounds(0);
+                POINT pt = new POINT();
+                int imageList = OS.SendMessage (table.handle, OS.LVM_CREATEDRAGIMAGE, table.indexOf(selected), pt);
+                OS.ImageList_Draw(imageList, 0, hDC1, cell.x - bounds.x, cell.y - bounds.y, OS.ILD_SELECTED);
+                OS.ImageList_Destroy(imageList);
+            }
+            OS.SelectObject(hDC1, hOldBitmap);
+            OS.DeleteDC (hDC1);
+            OS.ReleaseDC (0, hDC);
+            Display display = table.getDisplay();
+            dragSourceImage = Image.win32_new(display, DWT.BITMAP, bitmap);
+            return dragSourceImage;
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TableDropTargetEffect.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.TableDropTargetEffect;
+
+import dwt.graphics.Point;
+import dwt.internal.win32.OS;
+import dwt.widgets.Table;
+import dwt.widgets.TableItem;
+
+/**
+ * This class provides a default drag under effect (eg. select, insert and scroll)
+ * when a drag occurs over a <code>Table</code>.
+ *
+ * <p>Classes that wish to provide their own drag under effect for a <code>Table</code>
+ * can extend the <code>TableDropTargetEffect</code> and override any applicable methods
+ * in <code>TableDropTargetEffect</code> to display their own drag under effect.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag under effect implementation.
+ *
+ * <p>The feedback value is either one of the FEEDBACK constants defined in
+ * class <code>DND</code> which is applicable to instances of this class,
+ * or it must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> effect constants.
+ * </p>
+ * <p>
+ * <dl>
+ * <dt><b>Feedback:</b></dt>
+ * <dd>FEEDBACK_SELECT, FEEDBACK_SCROLL</dd>
+ * </dl>
+ * </p>
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ *
+ * @since 3.3
+ */
+public class TableDropTargetEffect : DropTargetEffect {
+    static final int SCROLL_HYSTERESIS = 200; // milli seconds
+
+    int scrollIndex = -1;
+    long scrollBeginTime;
+    TableItem dropHighlight;
+
+    /**
+     * Creates a new <code>TableDropTargetEffect</code> to handle the drag under effect on the specified
+     * <code>Table</code>.
+     *
+     * @param table the <code>Table</code> over which the user positions the cursor to drop the data
+     */
+    public this(Table table) {
+        super(table);
+    }
+
+    int checkEffect(int effect) {
+        // Some effects are mutually exclusive.  Make sure that only one of the mutually exclusive effects has been specified.
+        if ((effect & DND.FEEDBACK_SELECT) !is 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE;
+        if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER;
+        return effect;
+    }
+
+    /**
+     * This implementation of <code>dragEnter</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>.
+     *
+     * For additional information see <code>DropTargetAdapter.dragEnter</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragEnter(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag enter event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     */
+    public void dragEnter(DropTargetEvent event) {
+        scrollBeginTime = 0;
+        scrollIndex = -1;
+        dropHighlight = null;
+    }
+
+    /**
+     * This implementation of <code>dragLeave</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>.
+     *
+     * For additional information see <code>DropTargetAdapter.dragLeave</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragLeave(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag leave event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     */
+    public void dragLeave(DropTargetEvent event) {
+        Table table = (Table) control;
+        int handle = table.handle;
+        if (dropHighlight !is null) {
+            LVITEM lvItem = new LVITEM ();
+            lvItem.stateMask = OS.LVIS_DROPHILITED;
+            OS.SendMessage(handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+            dropHighlight = null;
+        }
+        scrollBeginTime = 0;
+        scrollIndex = -1;
+    }
+
+    /**
+     * This implementation of <code>dragOver</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>. The class description
+     * lists the FEEDBACK constants that are applicable to the class.
+     *
+     * For additional information see <code>DropTargetAdapter.dragOver</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragOver(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag over event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     * @see DND#FEEDBACK_SELECT
+     * @see DND#FEEDBACK_SCROLL
+     */
+    public void dragOver(DropTargetEvent event) {
+        Table table = (Table) getControl();
+        int effect = checkEffect(event.feedback);
+        int handle = table.handle;
+        Point coordinates = new Point(event.x, event.y);
+        coordinates = table.toControl(coordinates);
+        LVHITTESTINFO pinfo = new LVHITTESTINFO();
+        pinfo.x = coordinates.x;
+        pinfo.y = coordinates.y;
+        OS.SendMessage(handle, OS.LVM_HITTEST, 0, pinfo);
+        if ((effect & DND.FEEDBACK_SCROLL) is 0) {
+            scrollBeginTime = 0;
+            scrollIndex = -1;
+        } else {
+            if (pinfo.iItem !is -1 && scrollIndex is pinfo.iItem && scrollBeginTime !is 0) {
+                if (System.currentTimeMillis() >= scrollBeginTime) {
+                    int top = Math.max (0, OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0));
+                    int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+                    int index = (scrollIndex - 1 < top) ? Math.max(0, scrollIndex - 1) : Math.min(count - 1, scrollIndex + 1);
+                    bool scroll = true;
+                    if (pinfo.iItem is top) {
+                        scroll = pinfo.iItem !is index;
+                    } else {
+                        RECT itemRect = new RECT ();
+                        itemRect.left = OS.LVIR_BOUNDS;
+                        if (OS.SendMessage (handle, OS.LVM_GETITEMRECT, pinfo.iItem, itemRect) !is 0) {
+                            RECT rect = new RECT ();
+                            OS.GetClientRect (handle, rect);
+                            POINT pt = new POINT ();
+                            pt.x = itemRect.left;
+                            pt.y = itemRect.top;
+                            if (OS.PtInRect (rect, pt)) {
+                                pt.y = itemRect.bottom;
+                                if (OS.PtInRect (rect, pt)) scroll = false;
+                            }
+                        }
+                    }
+                    if (scroll) {
+                        OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 0);
+                        table.redraw();
+                    }
+                    scrollBeginTime = 0;
+                    scrollIndex = -1;
+                }
+            } else {
+                scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+                scrollIndex = pinfo.iItem;
+            }
+        }
+
+        if (pinfo.iItem !is -1 && (effect & DND.FEEDBACK_SELECT) !is 0) {
+            TableItem item = table.getItem(pinfo.iItem);
+            if (dropHighlight !is item) {
+                LVITEM lvItem = new LVITEM();
+                lvItem.stateMask = OS.LVIS_DROPHILITED;
+                OS.SendMessage(handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+                lvItem.state = OS.LVIS_DROPHILITED;
+                OS.SendMessage(handle, OS.LVM_SETITEMSTATE, pinfo.iItem, lvItem);
+                dropHighlight = item;
+            }
+        } else {
+            if (dropHighlight !is null) {
+                LVITEM lvItem = new LVITEM ();
+                lvItem.stateMask = OS.LVIS_DROPHILITED;
+                OS.SendMessage(handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+                dropHighlight = null;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TextTransfer.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.TextTransfer;
+
+import dwt.internal.ole.win32.COM;
+import dwt.internal.win32.OS;
+
+/**
+ * The class <code>TextTransfer</code> provides a platform specific mechanism
+ * for converting plain text represented as a java <code>String</code>
+ * to a platform specific representation of the data and vice versa.
+ *
+ * <p>An example of a java <code>String</code> containing plain text is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     String textData = "Hello World";
+ * </code></pre>
+ *
+ * @see Transfer
+ */
+public class TextTransfer : ByteArrayTransfer {
+
+    private static TextTransfer _instance = new TextTransfer();
+    private static final String CF_UNICODETEXT = "CF_UNICODETEXT"; //$NON-NLS-1$
+    private static final String CF_TEXT = "CF_TEXT"; //$NON-NLS-1$
+    private static final int CF_UNICODETEXTID = COM.CF_UNICODETEXT;
+    private static final int CF_TEXTID = COM.CF_TEXT;
+
+private this() {}
+
+/**
+ * Returns the singleton instance of the TextTransfer class.
+ *
+ * @return the singleton instance of the TextTransfer class
+ */
+public static TextTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts plain text
+ * represented by a java <code>String</code> to a platform specific representation.
+ *
+ * @param object a java <code>String</code> containing text
+ * @param transferData an empty <code>TransferData</code> object; this object
+ *  will be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#javaToNative
+ */
+public void javaToNative (Object object, TransferData transferData){
+    if (!checkText(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    transferData.result = COM.E_FAIL;
+    String string = (String)object;
+    switch (transferData.type) {
+        case COM.CF_UNICODETEXT: {
+            int charCount = string.length ();
+            char[] chars = new char[charCount+1];
+            string.getChars (0, charCount, chars, 0);
+            int byteCount = chars.length * 2;
+            int newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, byteCount);
+            OS.MoveMemory(newPtr, chars, byteCount);
+            transferData.stgmedium = new STGMEDIUM();
+            transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+            transferData.stgmedium.unionField = newPtr;
+            transferData.stgmedium.pUnkForRelease = 0;
+            transferData.result = COM.S_OK;
+            break;
+        }
+        case COM.CF_TEXT: {
+            int count = string.length();
+            char[] chars = new char[count + 1];
+            string.getChars(0, count, chars, 0);
+            int codePage = OS.GetACP();
+            int cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+            if (cchMultiByte is 0) {
+                transferData.stgmedium = new STGMEDIUM();
+                transferData.result = COM.DV_E_STGMEDIUM;
+                return;
+            }
+            int lpMultiByteStr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, cchMultiByte);
+            OS.WideCharToMultiByte(codePage, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+            transferData.stgmedium = new STGMEDIUM();
+            transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+            transferData.stgmedium.unionField = lpMultiByteStr;
+            transferData.stgmedium.pUnkForRelease = 0;
+            transferData.result = COM.S_OK;
+            break;
+        }
+    }
+    return;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of plain text to a java <code>String</code>.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java <code>String</code> containing text if the conversion was successful; otherwise null
+ *
+ * @see Transfer#nativeToJava
+ */
+public Object nativeToJava(TransferData transferData){
+    if (!isSupportedType(transferData) || transferData.pIDataObject is 0) return null;
+
+    IDataObject data = new IDataObject(transferData.pIDataObject);
+    data.AddRef();
+    FORMATETC formatetc = transferData.formatetc;
+    STGMEDIUM stgmedium = new STGMEDIUM();
+    stgmedium.tymed = COM.TYMED_HGLOBAL;
+    transferData.result = data.GetData(formatetc, stgmedium);
+    data.Release();
+    if (transferData.result !is COM.S_OK) return null;
+    int hMem = stgmedium.unionField;
+    try {
+        switch (transferData.type) {
+            case CF_UNICODETEXTID: {
+                /* Ensure byteCount is a multiple of 2 bytes */
+                int size = OS.GlobalSize(hMem) / 2 * 2;
+                if (size is 0) return null;
+                char[] chars = new char[size/2];
+                int ptr = OS.GlobalLock(hMem);
+                if (ptr is 0) return null;
+                try {
+                    OS.MoveMemory(chars, ptr, size);
+                    int length = chars.length;
+                    for (int i=0; i<chars.length; i++) {
+                        if (chars [i] is '\0') {
+                            length = i;
+                            break;
+                        }
+                    }
+                    return new String (chars, 0, length);
+                } finally {
+                    OS.GlobalUnlock(hMem);
+                }
+            }
+            case CF_TEXTID: {
+                int lpMultiByteStr = OS.GlobalLock(hMem);
+                if (lpMultiByteStr is 0) return null;
+                try {
+                    int codePage = OS.GetACP();
+                    int cchWideChar = OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, null, 0);
+                    if (cchWideChar is 0) return null;
+                    char[] lpWideCharStr = new char [cchWideChar - 1];
+                    OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, lpWideCharStr, lpWideCharStr.length);
+                    return new String(lpWideCharStr);
+                } finally {
+                    OS.GlobalUnlock(hMem);
+                }
+            }
+        }
+    } finally {
+        OS.GlobalFree(hMem);
+    }
+    return null;
+}
+
+protected int[] getTypeIds(){
+    return new int[] {CF_UNICODETEXTID, CF_TEXTID};
+}
+
+protected String[] getTypeNames(){
+    return new String[] {CF_UNICODETEXT, CF_TEXT};
+}
+
+bool checkText(Object object) {
+    return (object !is null  && object instanceof String && ((String)object).length() > 0);
+}
+
+protected bool validate(Object object) {
+    return checkText(object);
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/Transfer.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.Transfer;
+
+
+import dwt.internal.win32.OS;
+
+import dwt.dnd.TransferData;
+
+/**
+ * <code>Transfer</code> provides a mechanism for converting between a java
+ * representation of data and a platform specific representation of data and
+ * vice versa.  It is used in data transfer operations such as drag and drop and
+ * clipboard copy/paste.
+ *
+ * <p>You should only need to become familiar with this class if you are
+ * implementing a Transfer subclass and you are unable to subclass the
+ * ByteArrayTransfer class.</p>
+ *
+ * @see ByteArrayTransfer
+ */
+public abstract class Transfer {
+
+/**
+ * Returns a list of the platform specific data types that can be converted using
+ * this transfer agent.
+ *
+ * <p>Only the data type fields of the <code>TransferData</code> objects are filled
+ * in.</p>
+ *
+ * @return a list of the data types that can be converted using this transfer agent
+ */
+abstract public TransferData[] getSupportedTypes();
+
+/**
+ * Returns true if the <code>TransferData</code> data type can be converted
+ * using this transfer agent, or false otherwise (including if transferData is
+ * <code>null</code>).
+ *
+ * @param transferData a platform specific description of a data type; only the data
+ *  type fields of the <code>TransferData</code> object need to be filled in
+ *
+ * @return true if the transferData data type can be converted using this transfer
+ * agent
+ */
+abstract public bool isSupportedType(TransferData transferData);
+
+/**
+ * Returns the platform specific ids of the  data types that can be converted using
+ * this transfer agent.
+ *
+ * @return the platform specific ids of the data types that can be converted using
+ * this transfer agent
+ */
+abstract protected int[] getTypeIds();
+
+/**
+ * Returns the platform specific names of the  data types that can be converted
+ * using this transfer agent.
+ *
+ * @return the platform specific names of the data types that can be converted
+ * using this transfer agent.
+ */
+abstract protected char[][] getTypeNames();
+
+/**
+ * Converts a java representation of data to a platform specific representation of
+ * the data.
+ *
+ * <p>On a successful conversion, the transferData.result field will be set as follows:
+ * <ul>
+ * <li>Windows: COM.S_OK
+ * <li>Motif: 1
+ * <li>GTK: 1
+ * <li>Photon: 1
+ * </ul></p>
+ *
+ * <p>If this transfer agent is unable to perform the conversion, the transferData.result
+ * field will be set to a failure value as follows:
+ * <ul>
+ * <li>Windows: COM.DV_E_TYMED or COM.E_FAIL
+ * <li>Motif: 0
+ * <li>GTK: 0
+ * <li>Photon: 0
+ * </ul></p>
+ *
+ * @param object a java representation of the data to be converted; the type of
+ * Object that is passed in is dependent on the <code>Transfer</code> subclass.
+ *
+ * @param transferData an empty TransferData object; this object will be
+ * filled in on return with the platform specific representation of the data
+ *
+ * @exception dwt.DWTException <ul>
+ *    <li>ERROR_INVALID_DATA - if object does not contain data in a valid format or is <code>null</code></li>
+ * </ul>
+ */
+abstract public void javaToNative (Object object, TransferData transferData);
+
+/**
+ * Converts a platform specific representation of data to a java representation.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * converted
+ *
+ * @return a java representation of the converted data if the conversion was
+ * successful; otherwise null.  If transferData is <code>null</code> then
+ * <code>null</code> is returned.  The type of Object that is returned is
+ * dependent on the <code>Transfer</code> subclass.
+ */
+abstract public Object nativeToJava(TransferData transferData);
+
+/**
+ * Registers a name for a data type and returns the associated unique identifier.
+ *
+ * <p>You may register the same type more than once, the same unique identifier
+ * will be returned if the type has been previously registered.</p>
+ *
+ * <p>Note: On windows, do <b>not</b> call this method with pre-defined
+ * Clipboard Format types such as CF_TEXT or CF_BITMAP because the
+ * pre-defined identifier will not be returned</p>
+ *
+ * @param formatName the name of a data type
+ *
+ * @return the unique identifier associated with this data type
+ */
+public static int registerType(char[] formatName) {
+    // Look name up in the registry
+    // If name is not in registry, add it and return assigned value.
+    // If name already exists in registry, return its assigned value
+    TCHAR chFormatName = new TCHAR(0, formatName, true);
+    return OS.RegisterClipboardFormat(chFormatName);
+}
+
+/**
+ * Test that the object is of the correct format for this Transfer class.
+ *
+ * @param object a java representation of the data to be converted
+ *
+ * @return true if object is of the correct form for this transfer type
+ *
+ * @since 3.1
+ */
+public bool validate(Object object) {
+    return true;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TransferData.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.TransferData;
+
+import dwt.internal.ole.win32.COM;
+import dwt.internal.ole.win32.OBJIDL;
+
+/**
+ * The <code>TransferData</code> class is a platform specific data structure for
+ * describing the type and the contents of data being converted by a transfer agent.
+ *
+ * <p>As an application writer, you do not need to know the specifics of
+ * TransferData.  TransferData instances are passed to a subclass of Transfer
+ * and the Transfer object manages the platform specific issues.
+ * You can ask a Transfer subclass if it can handle this data by calling
+ * Transfer.isSupportedType(transferData).</p>
+ *
+ * <p>You should only need to become familiar with the fields in this class if you
+ * are implementing a Transfer subclass and you are unable to subclass the
+ * ByteArrayTransfer class.</p>
+ */
+public class TransferData {
+    /**
+     * The type is a unique identifier of a system format or user defined format.
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     */
+    public int type;
+
+    /**
+     * The formatetc structure is a generalized data transfer format, enhanced to
+     * encompass a target device, the aspect, or view of the data, and
+     * a storage medium.
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     */
+    public FORMATETC* formatetc;
+
+    /**
+     * The stgmedium structure is a generalized global memory handle used for
+     * data transfer operations.
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     */
+    public STGMEDIUM* stgmedium;
+
+    /**
+     * The result field contains the result of converting a
+     * java data type into a platform specific value.
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     * <p>The value of result is 1 if the conversion was successful.
+     * The value of result is 0 if the conversion failed.</p>
+     */
+    public int result = COM.E_FAIL;
+
+    /**
+     * The pIDataObject is the address of an IDataObject OLE Interface which
+     * provides access to the data associated with the transfer.
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     */
+    public IDataObject pIDataObject;
+
+    static bool sameType(TransferData data1, TransferData data2) {
+        if (data1 is data2) return true;
+        if (data1 is null || data2 is null) return false;
+        return (data1.type is data2.type &&
+                data1.formatetc.cfFormat is data2.formatetc.cfFormat &&
+                data1.formatetc.dwAspect is data2.formatetc.dwAspect &&
+                data1.formatetc.tymed is data2.formatetc.tymed);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TreeDragSourceEffect.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.TreeDragSourceEffect;
+
+import dwt.DWT;
+import dwt.graphics.Image;
+import dwt.graphics.Rectangle;
+import dwt.internal.win32.OS;
+import dwt.widgets.Display;
+import dwt.widgets.Tree;
+import dwt.widgets.TreeItem;
+
+/**
+ * This class provides default implementations to display a source image
+ * when a drag is initiated from a <code>Tree</code>.
+ *
+ * <p>Classes that wish to provide their own source image for a <code>Tree</code> can
+ * extend <code>TreeDragSourceEffect</code> class and override the <code>TreeDragSourceEffect.dragStart</code>
+ * method and set the field <code>DragSourceEvent.image</code> with their own image.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag under effect implementation.
+ *
+ * @see DragSourceEffect
+ * @see DragSourceEvent
+ *
+ * @since 3.3
+ */
+public class TreeDragSourceEffect : DragSourceEffect {
+    Image dragSourceImage = null;
+
+    /**
+     * Creates a new <code>TreeDragSourceEffect</code> to handle drag effect
+     * from the specified <code>Tree</code>.
+     *
+     * @param tree the <code>Tree</code> that the user clicks on to initiate the drag
+     */
+    public this(Tree tree) {
+        super(tree);
+    }
+
+    /**
+     * This implementation of <code>dragFinished</code> disposes the image
+     * that was created in <code>TreeDragSourceEffect.dragStart</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragFinished(event)</code>
+     * to dispose the image in the default implementation.
+     *
+     * @param event the information associated with the drag finished event
+     */
+    public void dragFinished(DragSourceEvent event) {
+        if (dragSourceImage !is null) dragSourceImage.dispose();
+        dragSourceImage = null;
+    }
+
+    /**
+     * This implementation of <code>dragStart</code> will create a default
+     * image that will be used during the drag. The image should be disposed
+     * when the drag is completed in the <code>TreeDragSourceEffect.dragFinished</code>
+     * method.
+     *
+     * Subclasses that override this method should call <code>super.dragStart(event)</code>
+     * to use the image from the default implementation.
+     *
+     * @param event the information associated with the drag start event
+     */
+    public void dragStart(DragSourceEvent event) {
+        event.image = getDragSourceImage(event);
+    }
+
+    Image getDragSourceImage(DragSourceEvent event) {
+        if (dragSourceImage !is null) dragSourceImage.dispose();
+        dragSourceImage = null;
+        Tree tree = (Tree) control;
+        TreeItem[] selection = tree.getSelection();
+        if (selection.length is 0) return null;
+        int treeImageList = OS.SendMessage (tree.handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0);
+        if (treeImageList !is 0) {
+            int count = Math.min(selection.length, 10);
+            Rectangle bounds = selection[0].getBounds(0);
+            for (int i = 1; i < count; i++) {
+                bounds = bounds.union(selection[i].getBounds(0));
+            }
+            int hDC = OS.GetDC(0);
+            int hDC1 = OS.CreateCompatibleDC(hDC);
+            int bitmap = OS.CreateCompatibleBitmap(hDC, bounds.width, bounds.height);
+            int hOldBitmap = OS.SelectObject(hDC1, bitmap);
+            RECT rect = new RECT();
+            rect.right = bounds.width;
+            rect.bottom = bounds.height;
+            int hBrush = OS.GetStockObject(OS.WHITE_BRUSH);
+            OS.FillRect(hDC1, rect, hBrush);
+            for (int i = 0; i < count; i++) {
+                TreeItem selected = selection[i];
+                Rectangle cell = selected.getBounds(0);
+                int imageList = OS.SendMessage(tree.handle, OS.TVM_CREATEDRAGIMAGE, 0, selected.handle);
+                OS.ImageList_Draw(imageList, 0, hDC1, cell.x - bounds.x, cell.y - bounds.y, OS.ILD_SELECTED);
+                OS.ImageList_Destroy(imageList);
+            }
+            OS.SelectObject(hDC1, hOldBitmap);
+            OS.DeleteDC (hDC1);
+            OS.ReleaseDC (0, hDC);
+            Display display = tree.getDisplay();
+            dragSourceImage = Image.win32_new(display, DWT.BITMAP, bitmap);
+            return dragSourceImage;
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TreeDropTargetEffect.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.TreeDropTargetEffect;
+
+import dwt.graphics.Point;
+import dwt.internal.win32.OS;
+import dwt.widgets.Tree;
+import dwt.widgets.TreeItem;
+
+/**
+ * This class provides a default drag under effect (eg. select, insert, scroll and expand)
+ * when a drag occurs over a <code>Tree</code>.
+ *
+ * <p>Classes that wish to provide their own drag under effect for a <code>Tree</code>
+ * can extend the <code>TreeDropTargetEffect</code> class and override any applicable methods
+ * in <code>TreeDropTargetEffect</code> to display their own drag under effect.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag under effect implementation.
+ *
+ * <p>The feedback value is either one of the FEEDBACK constants defined in
+ * class <code>DND</code> which is applicable to instances of this class,
+ * or it must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> effect constants.
+ * </p>
+ * <p>
+ * <dl>
+ * <dt><b>Feedback:</b></dt>
+ * <dd>FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE, FEEDBACK_INSERT_AFTER, FEEDBACK_EXPAND, FEEDBACK_SCROLL</dd>
+ * </dl>
+ * </p><p>
+ * Note: Only one of the styles FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE or
+ * FEEDBACK_INSERT_AFTER may be specified.
+ * </p>
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ *
+ * @since 3.3
+ */
+public class TreeDropTargetEffect : DropTargetEffect {
+    static final int SCROLL_HYSTERESIS = 200; // milli seconds
+    static final int EXPAND_HYSTERESIS = 1000; // milli seconds
+
+    int dropIndex;
+    int scrollIndex;
+    long scrollBeginTime;
+    int expandIndex;
+    long expandBeginTime;
+    TreeItem insertItem;
+    bool insertBefore;
+
+    /**
+     * Creates a new <code>TreeDropTargetEffect</code> to handle the drag under effect on the specified
+     * <code>Tree</code>.
+     *
+     * @param tree the <code>Tree</code> over which the user positions the cursor to drop the data
+     */
+    public this(Tree tree) {
+        super(tree);
+    }
+
+    int checkEffect(int effect) {
+        // Some effects are mutually exclusive.  Make sure that only one of the mutually exclusive effects has been specified.
+        if ((effect & DND.FEEDBACK_SELECT) !is 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE;
+        if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER;
+        return effect;
+    }
+
+    /**
+     * This implementation of <code>dragEnter</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>.
+     *
+     * For additional information see <code>DropTargetAdapter.dragEnter</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragEnter(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag enter event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     */
+    public void dragEnter(DropTargetEvent event) {
+        dropIndex = -1;
+        insertItem = null;
+        expandBeginTime = 0;
+        expandIndex = -1;
+        scrollBeginTime = 0;
+        scrollIndex = -1;
+    }
+
+    /**
+     * This implementation of <code>dragLeave</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>.
+     *
+     * For additional information see <code>DropTargetAdapter.dragLeave</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragLeave(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag leave event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     */
+    public void dragLeave(DropTargetEvent event) {
+        Tree tree = (Tree) control;
+        int handle = tree.handle;
+        if (dropIndex !is -1) {
+            TVITEM tvItem = new TVITEM ();
+            tvItem.hItem = dropIndex;
+            tvItem.mask = OS.TVIF_STATE;
+            tvItem.stateMask = OS.TVIS_DROPHILITED;
+            tvItem.state = 0;
+            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
+            dropIndex = -1;
+        }
+        if (insertItem !is null) {
+            tree.setInsertMark(null, false);
+            insertItem = null;
+        }
+        expandBeginTime = 0;
+        expandIndex = -1;
+        scrollBeginTime = 0;
+        scrollIndex = -1;
+    }
+
+    /**
+     * This implementation of <code>dragOver</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>.
+     *
+     * For additional information see <code>DropTargetAdapter.dragOver</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragOver(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag over event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     * @see DND#FEEDBACK_SELECT
+     * @see DND#FEEDBACK_INSERT_BEFORE
+     * @see DND#FEEDBACK_INSERT_AFTER
+     * @see DND#FEEDBACK_SCROLL
+     */
+    public void dragOver(DropTargetEvent event) {
+        Tree tree = (Tree) getControl();
+        int effect = checkEffect(event.feedback);
+        int handle = tree.handle;
+        Point coordinates = new Point(event.x, event.y);
+        coordinates = tree.toControl(coordinates);
+        TVHITTESTINFO lpht = new TVHITTESTINFO ();
+        lpht.x = coordinates.x;
+        lpht.y = coordinates.y;
+        OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
+        int hItem = lpht.hItem;
+        if ((effect & DND.FEEDBACK_SCROLL) is 0) {
+            scrollBeginTime = 0;
+            scrollIndex = -1;
+        } else {
+            if (hItem !is -1 && scrollIndex is hItem && scrollBeginTime !is 0) {
+                if (System.currentTimeMillis() >= scrollBeginTime) {
+                    int topItem = OS.SendMessage(handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
+                    int nextItem = OS.SendMessage(handle, OS.TVM_GETNEXTITEM, hItem is topItem ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE, hItem);
+                    bool scroll = true;
+                    if (hItem is topItem) {
+                        scroll = nextItem !is 0;
+                    } else {
+                        RECT itemRect = new RECT ();
+                        itemRect.left = nextItem;
+                        if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, itemRect) !is 0) {
+                            RECT rect = new RECT ();
+                            OS.GetClientRect (handle, rect);
+                            POINT pt = new POINT ();
+                            pt.x = itemRect.left;
+                            pt.y = itemRect.top;
+                            if (OS.PtInRect (rect, pt)) {
+                                pt.y = itemRect.bottom;
+                                if (OS.PtInRect (rect, pt)) scroll = false;
+                            }
+                        }
+                    }
+                    if (scroll) {
+                        OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, nextItem);
+                        tree.redraw();
+                    }
+                    scrollBeginTime = 0;
+                    scrollIndex = -1;
+                }
+            } else {
+                scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+                scrollIndex = hItem;
+            }
+        }
+        if ((effect & DND.FEEDBACK_EXPAND) is 0) {
+            expandBeginTime = 0;
+            expandIndex = -1;
+        } else {
+            if (hItem !is -1 && expandIndex is hItem && expandBeginTime !is 0) {
+                if (System.currentTimeMillis() >= expandBeginTime) {
+                    if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem) !is 0) {
+                        TVITEM tvItem = new TVITEM ();
+                        tvItem.hItem = hItem;
+                        tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
+                        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
+                        if ((tvItem.state & OS.TVIS_EXPANDED) is 0) {
+                            OS.SendMessage (handle, OS.TVM_EXPAND, OS.TVE_EXPAND, hItem);
+                            tree.redraw();
+                        }
+                    }
+                    expandBeginTime = 0;
+                    expandIndex = -1;
+                }
+            } else {
+                expandBeginTime = System.currentTimeMillis() + EXPAND_HYSTERESIS;
+                expandIndex = hItem;
+            }
+        }
+        if (dropIndex !is -1 && (dropIndex !is hItem || (effect & DND.FEEDBACK_SELECT) is 0)) {
+            TVITEM tvItem = new TVITEM ();
+            tvItem.hItem = dropIndex;
+            tvItem.mask = OS.TVIF_STATE;
+            tvItem.stateMask = OS.TVIS_DROPHILITED;
+            tvItem.state = 0;
+            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
+            dropIndex = -1;
+        }
+        if (hItem !is -1 && hItem !is dropIndex && (effect & DND.FEEDBACK_SELECT) !is 0) {
+            TVITEM tvItem = new TVITEM ();
+            tvItem.hItem = hItem;
+            tvItem.mask = OS.TVIF_STATE;
+            tvItem.stateMask = OS.TVIS_DROPHILITED;
+            tvItem.state = OS.TVIS_DROPHILITED;
+            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
+            dropIndex = hItem;
+        }
+        if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 0 || (effect & DND.FEEDBACK_INSERT_AFTER) !is 0) {
+            bool before = (effect & DND.FEEDBACK_INSERT_BEFORE) !is 0;
+            /*
+            * Bug in Windows.  When TVM_SETINSERTMARK is used to set
+            * an insert mark for a tree and an item is expanded or
+            * collapsed near the insert mark, the tree does not redraw
+            * the insert mark properly.  The fix is to hide and show
+            * the insert mark whenever an item is expanded or collapsed.
+            * Since the insert mark can not be queried from the tree,
+            * use the Tree API rather than calling the OS directly.
+            */
+            TreeItem item = (TreeItem)tree.getDisplay().findWidget(tree.handle, hItem);
+            if (item !is null) {
+                if (item !is insertItem || before !is insertBefore) {
+                    tree.setInsertMark(item, before);
+                }
+                insertItem = item;
+                insertBefore = before;
+            } else {
+                if (insertItem !is null) {
+                    tree.setInsertMark(null, false);
+                }
+                insertItem = null;
+            }
+        } else {
+            if (insertItem !is null) {
+                tree.setInsertMark(null, false);
+            }
+            insertItem = null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/URLTransfer.d	Wed Feb 13 04:51:22 2008 +0100
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.dnd.URLTransfer;
+
+import java.net.URL;
+
+import dwt.internal.ole.win32.COM;
+import dwt.internal.win32.OS;
+
+/**
+ * The class <code>URLTransfer</code> provides a platform specific mechanism
+ * for converting text in URL format represented as a java <code>String[]</code>
+ * to a platform specific representation of the data and vice versa.  See
+ * <code>Transfer</code> for additional information. The first string in the
+ * array is mandatory and must contain the fully specified url.  The second
+ * string in the array is optional and if present contains the title for the
+ * page.
+ *
+ * <p>An example of a java <code>String[]</code> containing a URL is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     String[] urlData = new String[] {"http://www.eclipse.org", "Eclipse.org Main Page"};
+ * </code></pre>
+ */
+/*public*/ class URLTransfer : ByteArrayTransfer {
+
+    static URLTransfer _instance = new URLTransfer();
+    static final String CFSTR_INETURL = "UniformResourceLocator"; //$NON-NLS-1$
+    static final int CFSTR_INETURLID = registerType(CFSTR_INETURL);
+
+private this() {}
+
+/**
+ * Returns the singleton instance of the URLTransfer class.
+ *
+ * @return the singleton instance of the URLTransfer class
+ */
+public static URLTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts a URL and optionally a title
+ * represented by a java <code>String[]</code> to a platform specific representation.
+ * For additional information see <code>Transfer#javaToNative</code>.
+ *
+ * @param object a java <code>String[]</code> containing a URL and optionally, a title
+ * @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 (!checkURL(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    transferData.result = COM.E_FAIL;
+    // URL is stored as a null terminated byte array
+    String url = ((String[])object)[0];
+    int count = url.length();
+    char[] chars = new char[count + 1];
+    url.getChars(0, count, chars, 0);
+    int codePage = OS.GetACP();
+    int cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+    if (cchMultiByte is 0) {
+        transferData.stgmedium = new STGMEDIUM();
+        transferData.result = COM.DV_E_STGMEDIUM;
+        return;
+    }
+    int lpMultiByteStr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, cchMultiByte);
+    OS.WideCharToMultiByte(codePage, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+    transferData.stgmedium = new STGMEDIUM();
+    transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+    transferData.stgmedium.unionField = lpMultiByteStr;
+    transferData.stgmedium.pUnkForRelease = 0;
+    transferData.result = COM.S_OK;
+    return;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of a URL and optionally, a title to a java <code>String[]</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>String[]</code> containing a URL and optionally a title if the
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData){
+    if (!isSupportedType(transferData) || transferData.pIDataObject is 0) return null;
+    IDataObject data = new IDataObject(transferData.pIDataObject);
+    data.AddRef();
+    STGMEDIUM stgmedium = new STGMEDIUM();
+    FORMATETC formatetc = transferData.formatetc;
+    stgmedium.tymed = COM.TYMED_HGLOBAL;
+    transferData.result = data.GetData(formatetc, stgmedium);
+    data.Release();
+    if (transferData.result !is COM.S_OK) return null;
+    int hMem = stgmedium.unionField;
+    try {
+        int lpMultiByteStr = OS.GlobalLock(hMem);
+        if (lpMultiByteStr is 0) return null;
+        try {
+            int codePage = OS.GetACP();
+            int cchWideChar  = OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, null, 0);
+            if (cchWideChar is 0) return null;
+            char[] lpWideCharStr = new char [cchWideChar - 1];
+            OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, lpWideCharStr, lpWideCharStr.length);
+            return new String[]{new String(lpWideCharStr)};
+        } finally {
+            OS.GlobalUnlock(hMem);
+        }
+    } finally {
+        OS.GlobalFree(hMem);
+    }
+}
+
+protected int[] getTypeIds(){
+    return new int[] {CFSTR_INETURLID};
+}
+
+protected String[] getTypeNames(){
+    return new String[] {CFSTR_INETURL};
+}
+
+bool checkURL(Object object) {
+    if (object is null  || !(object instanceof String[]) || ((String[])object).length is 0) return false;
+    String[] strings = (String[])object;
+    if (strings[0] is null || strings[0].length() is 0) return false;
+    try {
+        new URL(strings[0]);
+    } catch (java.net.MalformedURLException e) {
+        return false;
+    }
+    return true;
+}
+
+protected bool validate(Object object) {
+    return checkURL(object);
+}
+}