private int SetData(long /*int*/ pFormatetc, long /*int*/ pmedium, int fRelease) {
   if (pFormatetc == 0 || pmedium == 0) return COM.E_INVALIDARG;
   FORMATETC formatetc = new FORMATETC();
   COM.MoveMemory(formatetc, pFormatetc, FORMATETC.sizeof);
   if (formatetc.cfFormat == CFSTR_PERFORMEDDROPEFFECT && formatetc.tymed == COM.TYMED_HGLOBAL) {
     STGMEDIUM stgmedium = new STGMEDIUM();
     COM.MoveMemory(stgmedium, pmedium, STGMEDIUM.sizeof);
     // TODO - this should be GlobalLock()
     long /*int*/[] ptrEffect = new long /*int*/[1];
     OS.MoveMemory(ptrEffect, stgmedium.unionField, OS.PTR_SIZEOF);
     int[] effect = new int[1];
     OS.MoveMemory(effect, ptrEffect[0], 4);
     dataEffect = osToOp(effect[0]);
   }
   if (fRelease == 1) {
     COM.ReleaseStgMedium(pmedium);
   }
   return 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;
  }
  private int QueryGetData(long /*int*/ pFormatetc) {
    if (transferAgents == 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 != 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(long /*int*/ riid, long /*int*/ ppvObject) {
    if (riid == 0 || ppvObject == 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 long /*int*/[] {iDropSource.getAddress()}, OS.PTR_SIZEOF);
      AddRef();
      return COM.S_OK;
    }

    if (COM.IsEqualGUID(guid, COM.IIDIDataObject)) {
      OS.MoveMemory(ppvObject, new long /*int*/[] {iDataObject.getAddress()}, OS.PTR_SIZEOF);
      AddRef();
      return COM.S_OK;
    }

    OS.MoveMemory(ppvObject, new long /*int*/[] {0}, OS.PTR_SIZEOF);
    return COM.E_NOINTERFACE;
  }