3
votes

Here's how to accept files from Windows Shell to Virtual TreeView: How do you drag and drop a file from Explorer Shell into a VirtualTreeView control in a Delphi application?

Here's how it looks if I set DROPEFFECT_LINK for the Effect parameter in OnDragOver:

DROPEFFECT_LINK in VTV

The question is: is it possible to alter the hint text to say 'Link "to something"'?

I think the answer has to do with IDragSourceHelper2::SetFlags (_DROPDESCRIPTION record), but I'm not sure if I can use that and where.

1
Are you ready to modify VT source?Victoria
The receiving app can use its IDropTarget.OnDragEnter and IDropTarget.OnDragOver events to change the CFSTR_DROPDESCRIPTION data in the provided IDataObject, and then invalidate the text in the IDropTarget.OnDragLeave event. The dragging app checks for new text and updates the drag window accordingly. See Drag & Drop Images and Drop Descriptions for MFC Applications for details. The article is for MFC, but can be adapted for any IDragSource/IDropTarget implementation.Remy Lebeau
Which, @Remy, requires VT source modification (with the current implementation)..Victoria
You could handle the OnCreateDragManager event and implement you own DragManager. In this way you can implement your own version of IDropTarget.DragEnter and IDropTarget.DragOver. No need to modify VT source code.Mads Boyd-Madsen

1 Answers

0
votes

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