2015-10-06 216 views
-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)) 
+0

您應該使用IFileDialog。 –

+0

ANSI API而不是Unicode? Windows將在內部將其解碼回寬字符字符串。使用'SendMessageW','SHBrowseForFolderW'和'SHGetPathFromIDListW',並使用寬字符類型。 – eryksun

+0

在這裏的每種情況下使用'addressof'都是不正確的。該結構需要一個ctypes對象來進入它的'_objects'字典,以保持所有有效的引用。分配'addressof'的結果只是分配一個沒有上下文的整數。然後使用它通過引用傳遞參數,而不是使用正確的'byref'函數。您尚未設置'argtypes',因此地址將被轉換爲C'int'值,這會截斷64位指針值。 – eryksun

回答

-1

我切換到unicode和寬字符類型由評論的建議。

問題是將其轉換爲LPARAM,然後解除引用,但是這些註釋將我引向LPARAM上的方法from_buffer

我設置lParam如下:

bi.lParam = LPARAM.from_buffer(c_wchar_p(path)) 
相關問題