Creating choose folder-dialog from Python using Windows API

-1

I'm trying to create a choose folder-dialog from Python, but I'm having problems setting the initial folder path for the dialog. I think it's a problem converting the string to a LPARAM when I'm setting the _BROWSEINFO structure.

bi.lParam = cast(path.encode("ascii", "ignore"), POINTER(LPARAM)).contents

I'm getting this error in the callback:

windll.user32.SendMessageA(handle, _BFFM_SETSELECTIONA, 1, lpdata)
ctypes.ArgumentError: argument 4: <class 'OverflowError'>: int too long to convert

Below is the code I'm using, it seems to work well except the call to SendMessageA.

I'm setting the _BROWSEINFO structure in 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))
python
winapi
python-3.x
ctypes
asked on Stack Overflow Oct 6, 2015 by jacob • edited Oct 6, 2015 by jacob

1 Answer

-1

I switched to unicode and the wide character type as suggested by the comments.

The problem was casting it to an LPARAM and then dereferencing, but the comments led me to the method from_buffer on LPARAM.

I set lParam as follows:

bi.lParam = LPARAM.from_buffer(c_wchar_p(path))
answered on Stack Overflow Oct 6, 2015 by jacob • edited Oct 6, 2015 by jacob

User contributions licensed under CC BY-SA 3.0