SHGetFolderPathW有时会产生错误-2147024773:文件名,目录名或卷标签语法不正确

时间:2018-12-05 02:33:28

标签: python ctypes

这可能与SHGetFolderPathW not working with japanese username有关,但是我怀疑使用Python ctypes会增加另一个麻烦。

我的代码:

import ctypes

# Folder ID values for get_folder_path()
CSIDL_APPDATA       = 26
CSIDL_LOCAL_APPDATA = 28

def get_folder_path(id):
    dll = ctypes.oledll.shell32
    buf = ctypes.create_unicode_buffer(300)
    dll.SHGetFolderPathW(None, id, None, 0, buf)
    return buf.value

在Python 2.7.14中,当由具有ASCII用户名的用户运行时,此方法有效。

有时在由具有非ASCII用户名的用户运行时有效。

具体来说,我们使用PyInstaller创建与我们的产品捆绑在一起的Helper Windows可执行文件。该产品随NSIS安装程序一起安装。 NSIS安装程序将运行该PyInstaller可执行文件,该可执行文件将调用上面的函数,该可执行文件将生成一个有效的unicode路径名,我们将其日志文件存储在其中。

我们的产品本身是一个不同的可执行文件,它也作为具有不同命令行参数的子进程运行相同的帮助程序PyInstaller可执行文件。帮助程序可执行文件调用相同的函数(上面),以确定将其日志文件放在何处。但是对于使用非ASCII用户名的用户,SHGetFolderPathW()调用会产生我最初粘贴的错误。

对于价值而言,os.environ['APPDATA']包含C:\Users\??????\AppData\Roaming,这就是为什么我们完全称呼SHGetFolderPathW()的原因。

这与我们的安装程序或产品无关。您可以在emacs shell缓冲区中的cmd.exe下以交互方式运行python时遇到相同的故障,而在普通的命令提示符窗口中以交互方式运行python会产生有效的unicode路径。

我以为Python 3.6.4通常会更好地处理Unicode字符串,因此会带来更好的结果。令我困扰的是,在这种情况下,它甚至不如Python 2.7.14那样有效:即使在顶级命令提示符窗口中,由value编写的unicode缓冲区的SHGetFolderPathW()为{ {1}}。并且C:\Users\??????\AppData\Roaming包含相同的字符串。

并在emacs shell缓冲区中交互运行,会产生与Python 2.7.14相同的错误。

坦率地说,我对这次失败感到困惑。如果实际上已经在这里被询问并回答了,请给我指出解决方案。我找不到它。

非常感谢!

1 个答案:

答案 0 :(得分:0)

无法在Windows 10 64位,Python 3.7 64位和Python 2.7 32位上复制。请注意,由于安装了中文输入法,因此我使用了中文,但是我希望日语也会得到类似的结果。结果在标准cmd.exe窗口中:

Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> dll=ctypes.oledll.shell32
>>> b=ctypes.create_unicode_buffer(300)
>>> dll.SHGetFolderPathW(None,28,None,0,b)
0
>>> b.value
'C:\\Users\\马克\\AppData\\Local'

Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> dll=ctypes.oledll.shell32
>>> b=ctypes.create_unicode_buffer(300)
>>> dll.SHGetFolderPathW(None,28,None,0,b)
0
>>> b.value # those are the correct Unicode escape codes for 马克
u'C:\\Users\\\u9a6c\u514b\\AppData\\Local'

所以我怀疑问题出在其他地方,也许在emacs shell缓冲区中运行?

现在在Python 2情况下,如果您尝试打印那些字符:

>>> s = u'C:\\Users\\\u9a6c\u514b\\AppData\\Local'
>>> print(s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\encodings\cp437.py", line 12, in encode
    return codecs.charmap_encode(input,errors,encoding_map)
UnicodeEncodeError: 'charmap' codec can't encode characters in position 9-10: character maps to <undefined>
>>> print s.encode('cp437','replace')
C:\Users\??\AppData\Local

如果在其他外壳中运行,则可能会将Unicode转换为外壳的编码,而忽略了如上例中的错误。