-1
我想從Python創建一個選擇文件夾對話框,但我在設置對話框的初始文件夾路徑時遇到問題。我認爲在設置_BROWSEINFO
結構時,將字符串轉換爲LPARAM
是個問題。使用Windows API創建從Python中選擇文件夾對話框
bi.lParam = cast(path.encode("ascii", "ignore"), POINTER(LPARAM)).contents
我得到這個錯誤在回調:
windll.user32.SendMessageA(handle, _BFFM_SETSELECTIONA, 1, lpdata)
ctypes.ArgumentError: argument 4: <class 'OverflowError'>: int too long to convert
下面是我使用的代碼,它似乎只是調用SendMessageA很好地工作。
我設置_BROWSEINFO
結構browse_folder
,
_WM_USER = 0x400
_BFFM_INITIALIZED = 1
_BFFM_SETSELECTIONA = _WM_USER + 102
_BFFM_SETSELECTIONW = _WM_USER + 103
_BIF_RETURNONLYFSDIRS = 0x00000001
_BIF_NEWDIALOGSTYLE = 0x00000040
_BFFCALLBACK = WINFUNCTYPE(None, HWND, UINT, LPARAM, LPARAM)
def _browse_callback(handle, umsg, lparam, lpdata):
if(umsg == _BFFM_INITIALIZED):
if(lpdata is not None):
windll.user32.SendMessageA(handle, _BFFM_SETSELECTIONA, 1, lpdata)
return 0
class _SHITEMID(Structure):
_fields_ = [
("cb", USHORT),
("abID", BYTE)]
class _ITEMIDLIST(Structure):
_fields_ = [
("mkid", POINTER(_SHITEMID))]
class _BROWSEINFO(Structure):
_fields_ = [
("hwndOwner", HWND),
("pidlRoot", UINT),
("pszDisplayName", LPCSTR),
("lpszTitle", LPCSTR),
("ulFlags", UINT),
("lpfn", _BFFCALLBACK),
("lParam", LPARAM),
("iImage", INT)]
def browse_folder(path, message):
display_name = create_string_buffer(MAX_PATH)
end_path = create_string_buffer(MAX_PATH)
pidl_root = _ITEMIDLIST()
bi = _BROWSEINFO()
bi.hwndOwner = 0
bi.pidlRoot = 0
bi.pszDisplayName = addressof(display_name)
bi.lpszTitle = message.encode("ascii", "ignore")
bi.ulFlags = _BIF_RETURNONLYFSDIRS | _BIF_NEWDIALOGSTYLE
bi.lpfn = _BFFCALLBACK(_browse_callback)
bi.lParam = cast(path.encode("ascii", "ignore"), POINTER(LPARAM)).contents
bi.iImage = 0
pidl = windll.shell32.SHBrowseForFolder(addressof(bi))
print(display_name.value)
windll.shell32.SHGetPathFromIDList(pidl, addressof(end_path))
print(repr(end_path.value))
您應該使用IFileDialog。 –
ANSI API而不是Unicode? Windows將在內部將其解碼回寬字符字符串。使用'SendMessageW','SHBrowseForFolderW'和'SHGetPathFromIDListW',並使用寬字符類型。 – eryksun
在這裏的每種情況下使用'addressof'都是不正確的。該結構需要一個ctypes對象來進入它的'_objects'字典,以保持所有有效的引用。分配'addressof'的結果只是分配一個沒有上下文的整數。然後使用它通過引用傳遞參數,而不是使用正確的'byref'函數。您尚未設置'argtypes',因此地址將被轉換爲C'int'值,這會截斷64位指針值。 – eryksun