关于文件拷贝粘贴的剧难问题 ( 积分: 100 )

  • 主题发起人 主题发起人 墨剑
  • 开始时间 开始时间

墨剑

Unregistered / Unconfirmed
GUEST, unregistred user!
在我的程序中,我把文件经过压缩和加密然后传到FTP服务器上,需要这些文件的时候也是通过我的程序从FTP服务器上下载然后解密解压,最后存在用户指定的位置.我在程序中只提供文件的列表给用户看. 现在的问题是当用户在这些列表上选择"拷贝"以后,他到桌面上去来个右键,这是是否右键里面会有"粘贴"? 如果有,他选了粘贴之后,我的程序又怎么知道,并且要去下载他复制的文件进行解密解压最后保存在桌面上? 此起一也.
其二,当用户在桌面上复制了一个文件以后,在我的程序里面是否能给他一个粘贴的按钮? 当他点粘贴的时候我要能知道他复制的是哪些文件并且将这些文件进行处理并传到服务器上?
这两个问题困扰了我好几天,就是没有思路,希望高手能赐教一二.
 
当然要提供复制粘贴功能,实质就是下载,
是tidftp控件吧.
把选中的目录一起下载,自己递归来搞,因为get过程只能下载单个文件
 
lisongmagic,你把我的意思搞错了. 重点不是上传或下载,而是怎么拦截windows的粘贴动作
 
用勾子吧
 
钩子我用过啊,但怎么也拦截不到windows的粘贴动作,不知道是怎么回事
 
复制好做,粘贴的话唯有hook api
 
应该是通过剪贴板吧

一、把文件复制到Clipboard,这样就可以直接粘贴到桌面了。(这个在网上找的,没试过不知有没用)
uses shlobj,activex,clipbrd;
procedure Tform1.copytoclipbrd(var FileName:string);
var
FE:TFormatEtc;
Medium: TStgMedium;
dropfiles:PDropFiles;
pFile:PChar;
begin
FE.cfFormat := CF_HDROP;
FE.dwAspect := DVASPECT_CONTENT;
FE.tymed := TYMED_HGLOBAL;
Medium.hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_ZEROINIT, SizeOf(TDropFiles)+length(FileName)+1);
if Medium.hGlobal<>0 then begin
Medium.tymed := TYMED_HGLOBAL;
dropfiles := GlobalLock(Medium.hGlobal);
try
dropfiles^.pfiles := SizeOf(TDropFiles);
dropfiles^.fwide := False;
longint(pFile) := longint(dropfiles)+SizeOf(TDropFiles);
StrPCopy(pFile,FileName);
Inc(pFile, Length(FileName)+1);
pFile^ := #0;
finally
GlobalUnlock(Medium.hGlobal);
end;
Clipboard.SetAsHandle(CF_HDROP,Medium.hGlobal);
end;
end;

二、当用户在桌面上复制了一个文件以后,要粘贴就简单了
uses
Clipbrd, ShellAPI;

procedure GetClipFileNames(Strings: TStrings);
var
CHandle: Cardinal;
I, Count: Integer;
StrBuf: array[0..MAX_PATH - 1] of Char;
begin
CHandle := Clipboard.GetAsHandle(CF_HDROP);
I := -1;
Count := DrayQueryFile(CHandle, I, StrBuf, 0);
for I := 0 to Count - 1 do
if DrayQueryFile(CHandle, I, StrBuf, MAX_PATH) > 0 then
Strings.Add(StrBuf);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if Clipboard.HasFormat(CF_HDROP) then //判断是不是复制了文件在Clipboard
GetClipFileNames(Memo1.Lines);
end;
 
楼上说的这两个函数不能解决我的问题,因为最大的难题是放入剪切板的不是有效的文件名,此时真正的文件还在服务器上能,还没有解密解压,windows又怎能在点击了"粘贴"按钮之后自动去下载下来解密解压,哈哈.
 
何必一定要搞那么多钩子呢,直接在你的程序中的文件列表的右键菜单中提供"另存为"就行了.不提供粘贴复制等功能就是了.另外那个粘贴动作实际上是explorer程序的动作.
 
楼主的想法其实很好

我试验了一下flashfxp,也没有提供楼主所说的内容
 
有的啊,flashfxp我用了好多年了
 
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3701655

同类问题,正在研究
 
以前写的一个监视剪贴板的程序,希望对你有用 记得给分哟

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs,
Jpeg,shlobj,activex,clipbrd, StdCtrls, ExtCtrls;//加入clipbrd单元

type
TForm1 = class(TForm)
Timer1: TTimer;
Image1: TImage;
Memo1: TMemo;
CheckBox1: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject;
var Action: TCloseAction);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
NextClipHwnd:HWND;//观察链中下一个窗口句柄
procedure WMDrawClipBoard(var AMessage:TMessage);message WM_DRAWCLIPBOARD;
//处理WM_DRAWCLIPBOARD消息过程
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

{ TForm1 }

procedure copyfiletoclip(Filename:string);
//const FileName:string='c:/1.bmp'+#0+'c:/2.bmp'+#0;
var
DataHandle: THandle;
DataPointer: PDROPFILES;
begin
DataHandle := GlobalAlloc(GMEM_DDESHARE or GMEM_MOVEABLE,SizeOf(DROPFILES)+2+Length(FileName));
DataPointer := PDROPFILES(GlobalLock(DataHandle));
FillChar(DataPointer^,SizeOf(DROPFILES)+2+Length(FileName),0);

DataPointer.pFiles:=SizeOf(DROPFILES);
DataPointer.pt:=Point(0,0);
DataPointer.fNC:=False;
DataPointer.fWide:=False;
Move(FileName[1],Pointer(Integer(DataPointer)+SizeOf(DROPFILES))^,Length(FileName));
GlobalUnlock(DataHandle);
OpenClipboard(Form1.Handle);
EmptyClipboard;
SetClipboardData(CF_HDROP, DataHandle);
CloseClipboard;
end;


procedure TForm1.WMDrawClipBoard(var AMessage: TMessage);
var
BitMap1:TBitMap;
JPeg: TJPegImage;
filename: string;
begin
//将WM_DRAWCLIPBOARD
//消息传递到下一个观察链中的窗口
SendMessage(NextClipHwnd,AMessage.Msg,AMessage.WParam,AMessage.LParam);
//查询剪贴板中特定格式的数据内容
if (Clipboard.HasFormat(CF_TEXT) or Clipboard.HasFormat(CF_OEMTEXT)) then
begin

memo1.Lines.Clear;
memo1.Text:=Clipboard.asText;
if not checkbox1.Checked then
begin
memo1.Lines.SaveToFile('c:/readme.txt');

copyfiletoclip('c:/readme.txt');
end
else begin
filename:= memo1.Lines.Strings[0];
memo1.Lines.SaveToFile('c:/'+trim(filename)+'.txt');

copyfiletoclip('c:/'+trim(filename)+'.txt');

end;

//处理剪贴板中内容
// Caption:=Clipboard.asText;

end;

if Clipboard.HasFormat(CF_BITMAP) then
begin
Image1.Picture.Assign(Clipboard);
BitMap1 := TBitMap.Create;
BitMap1.Height := Image1.Picture.Height;
BitMap1.Width := Image1.Picture.Width;
BitMap1.Canvas.Draw(0,0,Image1.Picture.Graphic);

JPeg := TJPegimage.Create;
JPeg.Assign(Image1.Picture.Bitmap);
JPeg.SaveToFile('c:/logo.jpg');
JPeg.Free;

// BitMap1.SaveToFile('C:/New.bmp');
BitMap1.Free;
copyfiletoclip('c:/logo.jpg');
end;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin

//获得观察链中下一个窗口句柄
NextClipHwnd:=SetClipBoardViewer(Handle);

end;

procedure TForm1.FormClose
(Sender: TObject; var Action: TCloseAction);
begin
//从观察链中删除本观察窗口
ChangeClipboardChain(Handle,NextClipHwnd);
//将WM_DRAWCLIPBOARD
//消息传递到下一个观察链中的窗口
SendMessage(NextClipHwnd,WM_CHANGECBCHAIN,Handle,NextClipHwnd);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin


// FlashWindow(Form1.Handle,TRUE);
end;

end.
 
用 IDropTarget,IDataObject 和 IDropSource 接口能实现explorer(或其他支持此接口的程序)和你的程序之间互相拖动文件,文字等,右键菜单的互动我想也有类似的接口吧。
 
是勒,用IDropTarget,IDataObject 和 IDropSource 接口能实现explorer,你的答案最正确,但是这样做却是非常的复杂. 如果这个功能在程序中价值不是很高的话就得不偿失. 只想有点简单的办法.
 
其实问题主要在于文件不在本地,也就是说文件是动态生成的,还有个下载的过程,不知道楼上两位是怎么考虑的,Vc倒是有个例子,不过也不太好用
 
看看这个:
剪贴板延迟提交(Delayed rendering)技术,即由数据提供进程先创建一个指定数据格式的空(NULL)剪贴板数据块,直到有其他进程需要数据或自身进程要终止运行时才真正提交数据。

延迟提交的实现并不复杂,只需剪贴板拥有者进程在调用SetClipboardData()将数据句柄参数设置为NULL即可。延迟提交的拥有者进程需要做的主要工作是对WM_RENDERFORMAT、WM_DESTORYCLIPBOARD和WM_RENDERALLFORMATS等剪贴板延迟提交消息的处理。

当另一个进程调用GetClipboardData()函数时,系统将会向延迟提交数据的剪贴板拥有者进程发送WM_RENDERFORMAT消息。剪贴板拥有者进程在此消息的响应函数中应使用相应的格式和实际的数据句柄来调用SetClipboardData()函数,但不必再调用OpenClipboard()和EmptyClipboard()去打开和清空剪贴板了。在设置完数据有也无须调用CloseClipboard()关闭剪贴板。如果其他进程打开了剪贴板并且调用EmptyClipboard()函数去清空剪贴板的内容,接管剪贴板的拥有权时,系统将向延迟提交的剪贴板拥有者进程发送WM_DESTROYCLIPBOARD消息,以通知该进程对剪贴板拥有权的丧失。而失去剪贴板拥有权的进程在收到该消息后则不会再向剪贴板提交数据。另外,在延迟提交进程在提交完所有要提交的数据后也会收到此消息。如果延迟提交剪贴板拥有者进程将要终止,系统将会为其发送一条WM_RENDERALLFORMATS消息,通知其打开并清除剪贴板内容。在调用SetClipboardData()设置各数据句柄后关闭剪贴板。
 
剪贴板延迟提交技术针对的不是文件
 
本来就是高难度技术,但你又说 "这个功能在程序中价值不是很高的话就得不偿失",
那么你还是选择放弃这个方案吧,没简单的方法可以实现的。
 
程序的难度和价值有的时候并不成正比关系的,呵呵.

0桁骀所说的剪贴板延迟提交(Delayed rendering)技术,是在windows点击右键菜单的时候触发的,并不是在粘贴的时候触发,所以不可行.一是在点击右键的时候处理,给用户一种右键非常慢的感觉,第二是用户点右键又不仅仅是为了粘贴,他也许想做的是排列图标等等操作,那揪白费功夫了.

不知道大家注意qq群的共享没有,把共享里面的文件可以拖动到资源管理器,在资源管理器里就产生了一个后缀为qqt的文件,qq共享开始下载文件,当文件下载完了之后这个qqt文件就自动变成本身的文件名了.不知道是怎么实现的.
 
后退
顶部