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):
IDropTarget.OnDragEnter
andIDropTarget.OnDragOver
events to change theCFSTR_DROPDESCRIPTION
data in the providedIDataObject
, and then invalidate the text in theIDropTarget.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 anyIDragSource
/IDropTarget
implementation. – Remy Lebeau