You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows 7下Shell API IFileOperation复制无盘符文件报接口不支持错误

问题:Windows 7下使用IFileOperation复制手机无盘符文件报错解决

我正在使用Windows Shell API的IFileOperation接口,将USB连接的手机中的文件复制到电脑。由于手机存储没有盘符,常规的基于文件的复制函数(如os或shutil)无法实现该操作,因此采用以下代码:

import pythoncom
from win32comext.shell import shell, shellcon

fo = pythoncom.CoCreateInstance(shell.CLSID_FileOperation, None, pythoncom.CLSCTX_ALL, shell.IID_IFileOperation)

src = shell.SHCreateShellItem(...)     # 详见下方补充说明
dst = shell.SHCreateItemFromParsingName(path, None, shell.IID_IShellItem)
                                     # 这些对象已成功创建
                                     # 示例:<PyIShellFolder at 0x0000000002A6AB50 with obj at 0x0000000002ADA270>

fo.CopyItem(src, dst)     # 也测试过:fo.CopyItem(src, dst_folder, filename), fo.CopyItem(src, dst_folder, None, None) 等形式

fo.PerformOperations()    # 错误发生在该行

测试情况

  • 标准路径如C:\ABC\DEF\test.txt:在Win7和Win10上均可正常运行
  • 路径如This PC\Phone\card\DCIM\test.jpg:在Win10上可正常运行
  • 路径如Computer\Phone\card\DCIM\test.jpg:在Win7上运行失败,并出现以下错误(注意Win7中“This PC”名称为“Computer”)。

错误信息

pywintypes.com_error: (-2147467262, 'No such interface supported', None, None)

需求

如何让这段代码在Windows 7上正常运行?(仍需支持该平台)

补充说明

  • 与问题《Shell API to copy all files in a folder?》相关(该问题建议使用IFileOperation和CopyFile),但并非重复问题。
  • 同时涉及IFileOperation::PerformOperations返回E_NOINTERFACE的相关讨论。
  • 根据文档,IFileOperation::CopyItem自Windows Vista起便已支持。
  • 使用SHCreateShellItem创建src是因为需要递归遍历目录树:
for f in folder.EnumObjects(0, shellcon.SHCONTF_NONFOLDERS):
    srcfolder = shell.SHGetIDListFromObject(folder)
    src = shell.SHCreateShellItem(srcfolder, None, f)
    ...

另外,未使用shell.SHParseDisplayName或shell.SHCreateItemFromParsingName,因为它们在Win7上无法处理类似Computer\MyPhone\Card\myfiles\test.txt的路径。


解决办法

方法1:逐级枚举获取ShellItem(推荐)

Win7无法直接解析Computer\Phone\card\DCIM\test.jpg这类非文件系统路径,因此需要从Shell根节点(桌面)开始,逐级枚举子项获取目标文件的ShellItem,而非直接通过路径构造。示例代码如下:

import pythoncom
from win32comext.shell import shell, shellcon

def get_shell_item_by_hierarchy(root_item, path_parts):
    """从根ShellItem开始,逐级查找子项"""
    current_item = root_item
    for part in path_parts:
        found = False
        # 枚举当前目录的子项(包含文件夹和文件)
        for item in current_item.EnumObjects(0, shellcon.SHCONTF_FOLDERS | shellcon.SHCONTF_NONFOLDERS):
            item_name = item.GetDisplayName(shellcon.SHGDN_NORMAL)
            if item_name == part:
                current_item = item
                found = True
                break
        if not found:
            raise FileNotFoundError(f"找不到子项:{part}")
    return current_item

# 初始化COM
pythoncom.CoInitialize()

# 获取桌面ShellItem(Shell命名空间根节点)
desktop = shell.SHCreateItemFromParsingName("::{00021400-0000-0000-C000-000000000046}", None, shell.IID_IShellItem)
# 获取Win7的"Computer"(Win10对应"This PC")
computer = desktop.BindToHandler(None, shell.BHID_SFObject, shell.IID_IShellItem)

# 替换为你的手机存储路径层级,比如["Phone", "card", "DCIM", "test.jpg"]
src_path_parts = ["Phone", "card", "DCIM", "test.jpg"]
src = get_shell_item_by_hierarchy(computer, src_path_parts)

# 目标本地文件夹路径
dst_path = "C:\\TargetFolder"
dst = shell.SHCreateItemFromParsingName(dst_path, None, shell.IID_IShellItem)

# 执行复制操作
fo = pythoncom.CoCreateInstance(shell.CLSID_FileOperation, None, pythoncom.CLSCTX_ALL, shell.IID_IFileOperation)
# 设置操作选项(按需调整)
fo.SetOperationFlags(shellcon.FOF_NOCONFIRMATION | shellcon.FOF_SILENT | shellcon.FOF_NOERRORUI)
fo.CopyItem(src, dst)
fo.PerformOperations()

# 释放COM资源
pythoncom.CoUninitialize()

这种方式通过Shell层级枚举获取的ShellItem,在Win7上能被IFileOperation正确识别,避免路径解析的兼容性问题。

方法2:回退到旧API SHFileOperation

如果IFileOperation仍无法兼容,可使用旧的SHFileOperation API,它在Win7上对MTP设备的支持更稳定:

import pythoncom
from win32comext.shell import shell, shellcon
import win32api

# 初始化COM
pythoncom.CoInitialize()

# 假设已通过逐级枚举获取到src和dst的IShellItem对象
src_pidl = shell.SHGetIDListFromObject(src)
dst_pidl = shell.SHGetIDListFromObject(dst)

# 构造SHFILEOPSTRUCT结构体
fos = shell.SHFILEOPSTRUCT()
fos.hwnd = None
fos.wFunc = shellcon.FO_COPY
# pFrom和pTo需要是双空终止的字符串
fos.pFrom = shell.SHILCreateFromIDList(src_pidl, shell.IID_IShellItem).GetDisplayName(shellcon.SHGDN_FORPARSING) + '\x00\x00'
fos.pTo = shell.SHILCreateFromIDList(dst_pidl, shell.IID_IShellItem).GetDisplayName(shellcon.SHGDN_FORPARSING) + '\x00\x00'
# 设置操作选项
fos.fFlags = shellcon.FOF_NOCONFIRMATION | shellcon.FOF_SILENT | shellcon.FOF_NOERRORUI | shellcon.FOF_NOCONFIRMMKDIR

# 执行复制
result = shell.SHFileOperation(fos)
if result != 0:
    raise win32api.error(result, "SHFileOperation执行失败")

# 释放COM资源
pythoncom.CoUninitialize()

方法3:尝试转换为IShellItem2接口

部分Win7的Shell扩展可能需要IShellItem2接口支持,可尝试将src对象转换为该接口:

# 在创建src后添加以下代码
try:
    src_item2 = src.QueryInterface(shell.IID_IShellItem2)
    # 使用转换后的对象执行复制
    fo.CopyItem(src_item2, dst)
except pythoncom.com_error:
    # 转换失败,改用其他方法
    pass

内容的提问来源于stack exchange,提问作者Basj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 17:44:51