怎么将程序中的内容“拖”到桌面或文件夹中(DoDragDrop高难度高分有关问题)

如何将程序中的内容“拖”到桌面或文件夹中(DoDragDrop高难度高分问题)
实现拖出,

现在程序的数据源是Listview,具体的内容根据Listview选中的文件从ftp下载(这个无所谓,反正从其他地方来的,数据库的stream等等都可以,不同于普通文本拖放),希望拖放完毕,鼠标放开以后开始下载ftp的内容,并保存到本地,

(从程序窗口中的listview拖到桌面等地方)

不想用控件,主要想知道原理,如果哪位兄弟帮我把代码从控件中分离出来夜行,非常感谢

------解决方案--------------------
拖放要放在OLE对象里涉及到的API
DoDragDrop

DoDragDrop需要用到IDataObject,IDropSource
这个DELPHI没有申明需要自己做,过程要根据需要自己写了
关键过程为
GetData 向目标窗口传送数据
QueryGetData 目标窗口查询数据接口类型
其他可以直接Result := E_NOTIMPL;表示为接口不支持
还有个SetData接口,这个是将OLE数据存入IDataObject类,因为过程是自己写的,可以直接使用程序中的公共变量数据,不用通过SetData将数据写入IDataObject类

uses ShlObj,ActiveX, ComObj;
Tform1 = class(TForm, IDropSource)
....
....
Pubilc
//IDropSource
function QueryContinueDrag(fEscapePressed: BOOL; grfKeyState: Longint): HResult; stdcall;
function GiveFeedback(dwEffect: Longint): HResult; stdcall;
end;

TDataObject = class(TInterfacedObject,IDataObject)
public
constructor Create;
procedure Free;

function GetData(const formatetcIn: TFormatEtc; out medium: TStgMedium): HResult; stdcall;
function GetDataHere(const formatetc: TFormatEtc; out medium: TStgMedium): HResult; stdcall;
function QueryGetData(const formatetc: TFormatEtc): HResult; stdcall;
function GetCanonicalFormatEtc(const formatetc: TFormatEtc; out formatetcOut: TFormatEtc): HResult;stdcall;
function SetData(const formatetc: TFormatEtc; var medium: TStgMedium; fRelease: BOOL): HResult; stdcall;
function EnumFormatEtc(dwDirection: Longint; out enumFormatEtc: IEnumFormatEtc): HResult; stdcall;
function DAdvise(const formatetc: TFormatEtc; advf: Longint; const advSink: IAdviseSink; out dwConnection: Longint): HResult; stdcall;
function DUnadvise(dwConnection: Longint): HResult; stdcall;
function EnumDAdvise(out enumAdvise: IEnumStatData): HResult; stdcall;
end;

function Tform1.QueryContinueDrag(fEscapePressed: BOOL;
grfKeyState: Longint): HResult; stdcall;
begin
if fEscapePressed or (grfKeyState and MK_RBUTTON = MK_RBUTTON) then
Result := DRAGDROP_S_CANCEL
else
Result := DRAGDROP_S_DROP;
end;
function Tform1.GiveFeedback(dwEffect: Longint): HResult; stdcall;
begin
Result := DRAGDROP_S_USEDEFAULTCURSORS;
end;

//QueryGetData过程
function TDataObject.QueryGetData(const formatetc: TFormatEtc): HResult; stdcall;
begin
Result := DV_E_FORMATETC; //不支持的格式

if (formatetc.cfFormat=CF_HDROP) and //表示支持文件拖拽格式
(formatetc.tymed=TYMED_HGLOBAL ) and
(formatetc.dwAspect=DVASPECT_CONTENT) then
Result := S_OK;
end;

//GetData过程
function TDataObject.GetData(const formatetcIn: TFormatEtc; out medium: TStgMedium): HResult; stdcall;
var
BufferText : String;
pGlobal : Pointer;
begin
Result := DV_E_FORMATETC; //不支持的格式
if not (Self.QueryGetData(formatetcIn)=S_OK) then exit;
FillChar(Medium,Sizeof(TStgMedium),0);
Medium.tymed:=formatetcIn.tymed;
BufferText:= 'c:\temp\aa.txt '+#0+#0;
//需要拖拽的文件,多个的如下
// 'c:\temp\aa.txt '+#0+#0+ 'c:\temp\aa.txt '+#0+#0;+ 'c:\temp\aa.txt '+#0+#0;
Medium.hGlobal := GlobalAlloc(GMEM_ZEROINIT or GMEM_MOVEABLE or GMEM_SHARE, Length(BufferText)+1+Sizeof(TDropFiles));
pGlobal := GlobalLock(Medium.hGlobal);
PDropFiles(pGlobal)^.pFiles:=Sizeof(TDropFiles);
PDropFiles(pGlobal)^.pt:=Point(0,0);
PDropFiles(pGlobal)^.fNC:=False;
PDropFiles(pGlobal)^.fWide:=False;
inc(Longword(pGlobal),Sizeof(TDropFiles)); //指针后移