如何在WxPython应用中接收从Outlook拖拽的附件并获取文件内容
解决方案
问题根因
- wxPython 的
wx.DataObjectComposite默认仅自动拉取优先级最高的单种格式数据,不会主动获取所有注册格式的内容 FileContents属于延迟请求格式,Outlook 不会主动发送该格式数据,需要你在拿到FileGroupDescriptorW的文件名列表后,按附件索引主动请求对应内容- 当前代码使用 ANSI 版结构体规则解析 Unicode 格式的文件名,会出现乱码问题
完整可运行实现代码
import struct import wx class MainFrame(wx.Frame): def __init__(self, *args, **kwargs): wx.Frame.__init__(self, *args, **kwargs) self.drop_target = MyDropTarget() self.SetSize((800, 600)) self.SetDropTarget(self.drop_target) self.Center() class MyDropTarget(wx.DropTarget): def __init__(self): wx.DropTarget.__init__(self) # 注册三种拖拽格式 self.file_contents_format = wx.DataFormat("FileContents") self.file_group_format = wx.DataFormat("FileGroupDescriptor") self.file_group_w_format = wx.DataFormat("FileGroupDescriptorW") self.composite = wx.DataObjectComposite() self.file_contents_obj = wx.CustomDataObject(self.file_contents_format) self.file_group_obj = wx.CustomDataObject(self.file_group_format) self.file_group_w_obj = wx.CustomDataObject(self.file_group_w_format) # 优先取Unicode版的文件描述符 self.composite.Add(self.file_group_w_obj, preferred=True) self.composite.Add(self.file_group_obj) self.composite.Add(self.file_contents_obj) self.SetDataObject(self.composite) def OnDrop(self, x, y): return True def OnData(self, x, y, result): if not self.GetData(): return result recv_format = self.composite.GetReceivedFormat() # 先解析文件描述符获取文件名列表 filenames = [] if recv_format == self.file_group_w_format: # Unicode版结构体解析规则 小端序 data = self.file_group_w_obj.GetData() file_count = struct.unpack("<i", data[:4])[0] # FILEDESCRIPTORW 结构最后字段为520字节的宽字符文件名数组 fmt = "<i16s8s8si8s8s8sii520s" for item in struct.iter_unpack(fmt, data[4:]): # 解码宽字符文件名 filename = item[10].decode("utf-16-le").rstrip("\x00") filenames.append(filename) elif recv_format == self.file_group_format: # ANSI版结构体解析规则 data = self.file_group_obj.GetData() file_count = struct.unpack("<i", data[:4])[0] fmt = "<i16s8s8si8s8s8sii260s" for item in struct.iter_unpack(fmt, data[4:]): filename = item[10].decode("gbk").rstrip("\x00") filenames.append(filename) # 主动拉取每个附件的内容 for idx, filename in enumerate(filenames): # 指定要请求的附件索引 self.file_contents_obj.SetIndex(idx) # 主动请求当前索引对应的FileContents数据 if self.GetData(self.file_contents_format): file_content = self.file_contents_obj.GetData() # 保存到当前运行目录 with open(filename, "wb") as f: f.write(file_content) print(f"已成功保存附件:{filename}") return result if __name__ == "__main__": app = wx.App(redirect=False) frame = MainFrame(None, title="Outlook附件拖拽接收") frame.Show() app.MainLoop()
使用说明
- 运行程序后直接从Outlook邮件中拖拽附件到窗口区域即可自动保存到程序运行目录
- 支持单个、多个附件同时拖拽,兼容中文文件名
内容的提问来源于stack exchange,提问作者Anton Lahti
相关产品推荐
相关产品推荐

