荷兰语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)
三、关键修复点说明
修正路径缓冲区传递:
- 改用
c_wchar_p()接收API返回的路径指针,完全符合SHGetKnownFolderPath的参数要求。 - 使用后必须调用
CoTaskMemFree释放API分配的内存,这是Windows API的强制要求,否则会造成内存泄漏。
- 改用
明确API函数类型:
- 声明
argtypes和restype让ctypes正确处理参数和返回值,避免32位/64位Python环境下的类型不匹配错误,这在多架构系统中尤其重要。
- 声明
GUID结构优化:
- 调整了
string_to_guid函数,更清晰地拆分UUID字段,确保Data4的字节顺序完全匹配Windows GUID的标准格式。
- 调整了
四、额外排查建议
如果修复后仍有问题:
- 确认使用64位Python:如果你的Windows是64位版本,32位Python调用64位Shell32.dll可能出现兼容性问题,导致函数调用失败。
- 检查用户配置文件:如果用户配置文件损坏,标准文件夹可能被移动或丢失,可手动检查用户目录下的对应文件夹是否存在。
- 运行上下文:不要以管理员身份运行脚本,否则会切换到管理员用户上下文,可能无法访问当前普通用户的已知文件夹。
备注:内容来源于stack exchange,提问作者Barry Burgmeijer




