How to change drop hint (Delphi application) when doing drag-drop from Explorer Shell to Virtual TreeView?

Viewed 572
1 Answers

Shortly:
use IDataObject.SetData with FormatEtc.cfFormat=RegisterClipboardFormat(CFSTR_DROPDESCRIPTION) and DROPDESCRIPTION structure as TStgMedium content.

Drag source should call IDragSourceHelper2.SetFlags(DSH_ALLOWDROPDESCRIPTIONTEXT) before IDragSourceHelper.InitializeFromBitmap or IDragSourceHelper.InitializeFromWindow. VirtualTreeView set this flag automatically when it is used as drag source.


First, register special clipboard format.

constructor TForm12.Create(AOwner: TComponent);
begin
  inherited;
  FDragDescriptionFormat := RegisterClipboardFormat(PChar(CFSTR_DROPDESCRIPTION));
end;

Next, create method to set hint for IDataObject:

procedure TForm12.SetDragHint(DataObject: IDataObject; const Value: string; Effect: Integer);
var
  FormatEtc: TFormatEtc;
  Medium: TStgMedium;
  Data: Pointer;
  Descr: DROPDESCRIPTION;
  s: WideString;
begin
  ZeroMemory(@Descr, SizeOf(DROPDESCRIPTION));
  {Do not set Descr.&type to DROPIMAGE_INVALID - this value ignore any custom hint}
  {use same image as dropeffect type}
  Descr.&type := DROPIMAGE_LABEL;
  case Effect of
    DROPEFFECT_NONE:
      Descr.&type := DROPIMAGE_NONE;
    DROPEFFECT_COPY:
      Descr.&type := DROPIMAGE_COPY;
    DROPEFFECT_MOVE:
      Descr.&type := DROPIMAGE_MOVE;
    DROPEFFECT_LINK:
      Descr.&type := DROPIMAGE_LINK;
  end;
  {format message for system}
  if Length(Value) <= MAX_PATH then
  begin
    Move(Value[1], Descr.szMessage[0], Length(Value) * SizeOf(WideChar));
    Descr.szInsert := '';
  end
  else
  begin
    s := Copy(Value, 1, MAX_PATH - 2) + '%1';
    Move(s[1], Descr.szMessage[0], Length(s) * SizeOf(WideChar));

    s := Copy(Value, MAX_PATH - 1, MAX_PATH);
    Move(s[1], Descr.szInsert[0], Length(s) * SizeOf(WideChar));
  end;
  {prepare structures to set DROPDESCRIPTION data} 
  FormatEtc.cfFormat := FDragDescriptionFormat; {registered clipboard format}
  FormatEtc.ptd := nil;
  FormatEtc.dwAspect := DVASPECT_CONTENT;
  FormatEtc.lindex := -1;
  FormatEtc.tymed := TYMED_HGLOBAL;

  ZeroMemory(@Medium, SizeOf(TStgMedium));
  Medium.tymed := TYMED_HGLOBAL;
  Medium.HGlobal := GlobalAlloc(GHND or GMEM_SHARE, SizeOf(DROPDESCRIPTION));
  Data := GlobalLock(Medium.HGlobal);
  Move(Descr, Data^, SizeOf(DROPDESCRIPTION));
  GlobalUnlock(Medium.HGlobal);

  DataObject.SetData(FormatEtc, Medium, True);
end;

Last - use SetDragHint, for example - in VirtualTreeView.OnDragOver event:

procedure TForm12.vt1DragOver(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState;
  Pt: TPoint; Mode: TDropMode; var Effect: Integer; var Accept: Boolean);
begin
  Accept := True;
  Effect := DROPEFFECT_LINK;
  if State = dsDragMove then
  begin
    SetDragHint(vt1.DragManager.DataObject, Format('Point: (%d, %d)', [Pt.X, Pt.Y]), Effect);
  end
  else
  begin
    Accept := False;
    Effect := DROPEFFECT_NONE;
    SetDragHint(vt1.DragManager.DataObject, '', Effect);
  end;
end;

Result (drag file from Explorer to VirtualStringTree):

Screenshot

Related