You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

荷兰语Windows 10系统中使用GUID调用SHGetKnownFolderPath失败,错误码-2147024894

荷兰语Windows 10系统中使用GUID调用SHGetKnownFolderPath失败,错误码-2147024894

我之前也碰到过一模一样的问题,这个错误码对应的是Windows HRESULT 0x80070002(也就是ERROR_FILE_NOT_FOUND),但它的本质不是文件夹真的不存在,而是你的代码对SHGetKnownFolderPath的参数处理不符合API要求,再加上可能的32/64位Python兼容性问题。下面是具体的分析和修复方案:

一、核心错误原因

你的原代码中,传递路径缓冲区的方式是错误的:SHGetKnownFolderPath的第四个参数要求是PWSTR*(指向宽字符指针的指针),它会自行分配内存存储路径并返回指针;但你用了create_unicode_buffer创建固定大小的数组,直接传递它的引用,这不符合API的参数规范,导致函数无法正确写入路径,最终返回错误。

二、修复后的完整代码

import os
import ctypes
import logging
from ctypes import windll, byref, c_wchar_p, POINTER, Structure, c_uint32, c_uint16, c_uint8, c_void_p
from uuid import UUID

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
)

# 明确声明API函数的参数和返回值类型,避免类型不匹配错误
windll.shell32.SHGetKnownFolderPath.argtypes = [
    POINTER(Structure),
    c_uint32,
    c_void_p,  # HANDLE类型用c_void_p兼容32/64位
    POINTER(c_wchar_p)
]
windll.shell32.SHGetKnownFolderPath.restype = c_uint32

windll.ole32.CoTaskMemFree.argtypes = [c_void_p]
windll.ole32.CoTaskMemFree.restype = None

class GUID(Structure):
    """与ctypes兼容的GUID结构定义"""
    _fields_ = [
        ("Data1", c_uint32),
        ("Data2", c_uint16),
        ("Data3", c_uint16),
        ("Data4", c_uint8 * 8)
    ]

def string_to_guid(guid_string):
    """将GUID字符串转换为ctypes GUID结构"""
    guid = UUID(guid_string)
    # 正确拆分UUID的各个字段,匹配Windows GUID的字节顺序
    time_low, time_mid, time_hi_version, clock_seq_hi, clock_seq_low, *node_bytes = guid.fields
    data4 = (c_uint8 * 8)(clock_seq_hi, clock_seq_low, *node_bytes)
    return GUID(time_low, time_mid, time_hi_version, data4)

def get_known_folder_path(folder_id):
    """通过GUID获取Windows已知文件夹的路径"""
    try:
        guid = string_to_guid(folder_id)
        path_ptr = c_wchar_p()  # 用于接收API返回的路径指针
        
        result = windll.shell32.SHGetKnownFolderPath(
            byref(guid),
            0,  # 无特殊选项
            None,  # 使用当前进程的用户令牌
            byref(path_ptr)
        )
        
        if result == 0:
            path = path_ptr.value
            logging.info("找到文件夹: %s", path)
            # 释放API分配的内存,避免内存泄漏
            windll.ole32.CoTaskMemFree(path_ptr)
            return path
        else:
            logging.error("SHGetKnownFolderPath错误代码: %08X", result)
            return None
    except Exception as e:
        logging.error("获取文件夹时出错: %s", e)
        return None

if __name__ == "__main__":
    # 标准Windows已知文件夹的GUID(来自微软官方文档)
    known_folders = {
        "桌面": "{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}",
        "文档": "{FDD39AD0-238F-46AF-ADB4-6C85480369C7}",
        "图片": "{33E28130-4E1E-4676-835A-98395C3BC3BB}",
        "视频": "{18989B1D-99B5-455B-841C-AB7C74E4DDFC}",
        "下载": "{374DE290-123F-4565-9164-39C4925E467B}",
    }

    # 测试各个文件夹
    for folder_name, folder_guid in known_folders.items():
        logging.info("正在检查%s是否存在...", folder_name)
        folder_path = get_known_folder_path(folder_guid)
        if folder_path:
            logging.info("%s的路径: %s", folder_name, folder_path)
        else:
            logging.error("无法获取%s的路径。", folder_name)

三、关键修复点说明

  1. 修正路径缓冲区传递

    • 改用c_wchar_p()接收API返回的路径指针,完全符合SHGetKnownFolderPath的参数要求。
    • 使用后必须调用CoTaskMemFree释放API分配的内存,这是Windows API的强制要求,否则会造成内存泄漏。
  2. 明确API函数类型

    • 声明argtypesrestype让ctypes正确处理参数和返回值,避免32位/64位Python环境下的类型不匹配错误,这在多架构系统中尤其重要。
  3. GUID结构优化

    • 调整了string_to_guid函数,更清晰地拆分UUID字段,确保Data4的字节顺序完全匹配Windows GUID的标准格式。

四、额外排查建议

如果修复后仍有问题:

  • 确认使用64位Python:如果你的Windows是64位版本,32位Python调用64位Shell32.dll可能出现兼容性问题,导致函数调用失败。
  • 检查用户配置文件:如果用户配置文件损坏,标准文件夹可能被移动或丢失,可手动检查用户目录下的对应文件夹是否存在。
  • 运行上下文:不要以管理员身份运行脚本,否则会切换到管理员用户上下文,可能无法访问当前普通用户的已知文件夹。

备注:内容来源于stack exchange,提问作者Barry Burgmeijer

火山引擎 最新活动