如何在复制粘贴、移动与拖放操作的目标端执行指定操作?
我在开发Shell Namespace Extension时,希望用户从其中复制文件完成后立即执行某项资源密集型操作,要求必须等复制完全结束再启动处理,不能提前展示处理后的项目。
虽然在Folder和Directory类上实现Drop Handler是可行方案,但这会给终端用户带来操作限制——他们必须记住只能通过右键拖放复制,无法使用Ctrl+C/Ctrl+V等常规方式。因此需要找到能在常规复制完成后触发操作的方法。
已知IDataObject和ITransferSource接口(除ITransferSource::MoveItem外)都不提供数据目标的信息,这是IDataObject的设计初衷,因为目标可以是任意对象,源不应知晓其细节。针对此场景,以下是对应问题的解答:
是否可以在
IDataObject内部知晓数据接收方是资源管理器(Explorer)还是其他应用程序?
可以实现。拖放场景下,可获取目标窗口句柄后调用GetClassName,资源管理器的窗口类名是CabinetWClass或ExploreWClass;也可通过IDataObject::GetData请求CF_OWNERDISPLAY格式,资源管理器会响应该格式,多数其他应用程序不会。剪贴板复制场景下,可监控剪贴板所有者,但可靠性稍低,优先推荐拖放时的窗口类名检查方法。如果能确定拖放目标是资源管理器窗口,是否可以知晓目标文件夹的路径?
可以。向目标窗口发送WM_USER+1001(FCM_GETTARGETFOLDER)消息获取目标文件夹的PIDL,再通过SHGetPathFromIDList将PIDL转换为本地路径即可。该消息是资源管理器私有消息,仅对其窗口有效。是否可以知晓通过
IDataObject进行的复制操作是否成功完成(除了跟踪IStream是否被读取至末尾之外)?
没有原生接口直接支持。IDataObject设计为源提供数据、目标负责处理,源无法直接感知目标操作结果。拖放场景下,IDropSource::QueryContinueDrag仅能判断拖放是否被取消,无法确认复制成功;剪贴板复制场景更无法直接获取结果。可通过ReadDirectoryChangesW监控目标文件夹,检测文件是否出现且完成写入,间接判断复制是否成功。是否可以知晓
ITransferSource::OpenItem操作的目标路径?
不能。ITransferSource::OpenItem仅负责让源提供可读取的数据流,目标写入位置由目标自行决定,源无法获取该路径信息。是否可以知晓通过
ITransferSource::OpenItem进行的复制操作是否成功完成?
不能。ITransferSource接口设计中,源仅负责提供数据,目标的操作结果不会反馈给源。无法直接通过该接口获取复制成功状态,需依赖文件系统监控等外部手段间接判断。
内容的提问来源于stack exchange,提问作者ElDorado

