/**
   * 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 == 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 != 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;
  }
 /**
  * This implementation of <code>javaToNative</code> converts a list of file names represented by a
  * java <code>String[]</code> to a platform specific representation. Each <code>String</code> in
  * the array contains the absolute path for a single file or directory. For additional information
  * see <code>Transfer#javaToNative</code>.
  *
  * @param object a java <code>String[]</code> containing the file names to be converted
  * @param transferData an empty <code>TransferData</code> object; this object will be filled in on
  *     return with the platform specific format of the data
  */
 public void javaToNative(Object object, TransferData transferData) {
   if (!checkFile(object) || !isSupportedType(transferData)) {
     DND.error(DND.ERROR_INVALID_DATA);
   }
   String[] fileNames = (String[]) object;
   StringBuffer allFiles = new StringBuffer();
   for (int i = 0; i < fileNames.length; i++) {
     allFiles.append(fileNames[i]);
     allFiles.append(CF_HDROP_SEPARATOR); // each name is null terminated
   }
   TCHAR buffer =
       new TCHAR(
           0, allFiles.toString(), true); // there is an extra null terminator at the very end
   DROPFILES dropfiles = new DROPFILES();
   dropfiles.pFiles = DROPFILES.sizeof;
   dropfiles.pt_x = dropfiles.pt_y = 0;
   dropfiles.fNC = 0;
   dropfiles.fWide = OS.IsUnicode ? 1 : 0;
   // Allocate the memory because the caller (DropTarget) has not handed it in
   // The caller of this method must release the data when it is done with it.
   int byteCount = buffer.length() * TCHAR.sizeof;
   int /*long*/ newPtr =
       OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, DROPFILES.sizeof + byteCount);
   OS.MoveMemory(newPtr, dropfiles, DROPFILES.sizeof);
   OS.MoveMemory(newPtr + DROPFILES.sizeof, buffer, byteCount);
   transferData.stgmedium = new STGMEDIUM();
   transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
   transferData.stgmedium.unionField = newPtr;
   transferData.stgmedium.pUnkForRelease = 0;
   transferData.result = COM.S_OK;
 }
  private int GetData(long /*int*/ pFormatetc, long /*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 == 0 || pmedium == 0) return COM.E_INVALIDARG;

    if (QueryGetData(pFormatetc) != 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);

    if (!event.doit) return COM.E_FAIL;

    // get matching transfer agent to perform conversion
    Transfer transfer = null;
    for (int i = 0; i < transferAgents.length; i++) {
      Transfer transferAgent = transferAgents[i];
      if (transferAgent != null && transferAgent.isSupportedType(transferData)) {
        transfer = transferAgent;
        break;
      }
    }

    if (transfer == null) return COM.DV_E_FORMATETC;
    transfer.javaToNative(event.data, transferData);
    if (transferData.result != COM.S_OK) return transferData.result;
    COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof);
    return transferData.result;
  }