mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-13 07:47:14 +03:00
prefs.py: Attempting to fix non-utf-8 case of "choose Output file location"
1. `SHGetPathFromIDListW` needing fixing, which was achieved, but... 2. ... then `SHBrowseForFolderW()` as-was returned `int` instead of a pointer to the correct structure. Trying to fix 2 has proven intractable: a. Trying to cast the `int` return just results in `exception: access violation reading <address>`. b. Trying to define `SHBrowseForFolderW` properly, so it returns the correct type results in a *writing* access violation when called, despite passing the exact same data in as for the 'raw' call version. So, this commit is a record, and I'm next going to try switching to `IFileDialog` as recommended by the docs for `SHBrowseForFolderW` ('For Windows Vista or later').
This commit is contained in:
parent
f141fccd86
commit
da530f135e
81
prefs.py
81
prefs.py
@ -181,7 +181,10 @@ if sys.platform == 'darwin':
|
||||
elif sys.platform == 'win32':
|
||||
import ctypes
|
||||
import winreg
|
||||
from ctypes.wintypes import HINSTANCE, HWND, LPARAM, LPCWSTR, LPVOID, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT
|
||||
from ctypes import POINTER, WINFUNCTYPE, Structure
|
||||
from ctypes.wintypes import (
|
||||
BOOL, BYTE, HINSTANCE, HWND, LPARAM, LPCWSTR, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT, USHORT
|
||||
)
|
||||
is_wine = False
|
||||
try:
|
||||
WINE_REGISTRY_KEY = r'HKEY_LOCAL_MACHINE\Software\Wine'
|
||||
@ -192,18 +195,68 @@ elif sys.platform == 'win32':
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
###########################################################################
|
||||
# From <https://github.com/hakril/PythonForWindows/blob/master/windows/generated_def/winstructs.py>
|
||||
class _SHITEMID(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("cb", USHORT),
|
||||
("abID", BYTE * (1)),
|
||||
]
|
||||
|
||||
SHITEMID = _SHITEMID
|
||||
|
||||
class _ITEMIDLIST(Structure):
|
||||
_fields_ = [
|
||||
("mkid", SHITEMID),
|
||||
]
|
||||
|
||||
ITEMIDLIST = _ITEMIDLIST
|
||||
PCIDLIST_ABSOLUTE = ctypes.POINTER(_ITEMIDLIST)
|
||||
PIDLIST_ABSOLUTE = ctypes.POINTER(_ITEMIDLIST)
|
||||
###########################################################################
|
||||
|
||||
###########################################################################
|
||||
# From: <https://stackoverflow.com/questions/32979525/creating-choose-folder-dialog-from-python-using-windows-api>
|
||||
BrowseCallbackProc = WINFUNCTYPE(ctypes.c_int, HWND, ctypes.c_uint, LPARAM, LPARAM)
|
||||
|
||||
class BROWSEINFOW(ctypes.Structure):
|
||||
"""
|
||||
Windows file browser fields.
|
||||
|
||||
Ref: <https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfow>
|
||||
"""
|
||||
|
||||
_fields_ = [
|
||||
("hwndOwner", HWND),
|
||||
("pidlRoot", PCIDLIST_ABSOLUTE),
|
||||
("pszDisplayName", LPWSTR),
|
||||
("lpszTitle", LPCWSTR),
|
||||
("ulFlags", UINT),
|
||||
("lpfn", BrowseCallbackProc),
|
||||
("lParam", LPARAM),
|
||||
("iImage", ctypes.c_int)
|
||||
]
|
||||
LPBROWSEINFOW = POINTER(BROWSEINFOW)
|
||||
###########################################################################
|
||||
|
||||
# https://msdn.microsoft.com/en-us/library/windows/desktop/bb762115
|
||||
BIF_RETURNONLYFSDIRS = 0x00000001
|
||||
BIF_USENEWUI = 0x00000050
|
||||
BFFM_INITIALIZED = 1
|
||||
BFFM_SETSELECTION = 0x00000467
|
||||
BrowseCallbackProc = ctypes.WINFUNCTYPE(ctypes.c_int, HWND, ctypes.c_uint, LPARAM, LPARAM)
|
||||
# SHGetPathFromIDListW
|
||||
# Ref: <https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetpathfromidlistw>
|
||||
# BOOL SHGetPathFromIDListW([in] PCIDLIST_ABSOLUTE pidl,[out] LPWSTR pszPath);
|
||||
prototype = WINFUNCTYPE(BOOL, PCIDLIST_ABSOLUTE, LPCWSTR)
|
||||
paramflags = (1, "pidl"), (2, "pszPath", "")
|
||||
SHGetPathFromIDListW = prototype(("SHGetPathFromIDListW", ctypes.windll.shell32), paramflags)
|
||||
|
||||
class BROWSEINFO(ctypes.Structure):
|
||||
"""Windows file browser fields."""
|
||||
|
||||
_fields_ = [("hwndOwner", HWND), ("pidlRoot", LPVOID), ("pszDisplayName", LPWSTR), ("lpszTitle", LPCWSTR),
|
||||
("ulFlags", UINT), ("lpfn", BrowseCallbackProc), ("lParam", LPCWSTR), ("iImage", ctypes.c_int)]
|
||||
# SHBrowseForFolderW
|
||||
# Ref: <https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shbrowseforfolderw>
|
||||
# PIDLIST_ABSOLUTE SHBrowseForFolderW([in] LPBROWSEINFOWW lpbi);
|
||||
prototype = WINFUNCTYPE(PIDLIST_ABSOLUTE, LPBROWSEINFOW)
|
||||
paramflags2 = (1, "lpbi"),
|
||||
SHBrowseForFolderW = prototype(("SHGetPathFromIDListW", ctypes.windll.shell32), paramflags2)
|
||||
|
||||
CalculatePopupWindowPosition = None
|
||||
if not is_wine:
|
||||
@ -1037,17 +1090,23 @@ class PreferencesDialog(tk.Toplevel):
|
||||
ctypes.windll.user32.SendMessageW(hwnd, BFFM_SETSELECTION, 1, lpData)
|
||||
return 0
|
||||
|
||||
browseInfo = BROWSEINFO() # noqa: N806 # Windows convention
|
||||
browseInfo = BROWSEINFOW() # noqa: N806 # Windows convention
|
||||
# browseInfo.pidlRoot = None
|
||||
browseInfo.pszDisplayName = ctypes.c_wchar_p("x" * MAX_PATH)
|
||||
browseInfo.lpszTitle = title
|
||||
browseInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI
|
||||
browseInfo.lpfn = BrowseCallbackProc(browsecallback)
|
||||
browseInfo.lParam = pathvar.get().startswith('~') and join(config.home_path,
|
||||
pathvar.get()[2:]) or pathvar.get()
|
||||
# browseInfo.lParam = pathvar.get().startswith('~') and join(config.home_path,
|
||||
# pathvar.get()[2:]) or pathvar.get()
|
||||
ctypes.windll.ole32.CoInitialize(None)
|
||||
pidl = ctypes.windll.shell32.SHBrowseForFolderW(ctypes.byref(browseInfo))
|
||||
# ctypes.ArgumentError: argument 1: <class 'TypeError'>: expected LP__ITEMIDLIST instance instead of int
|
||||
# pidl = SHBrowseForFolderW(ctypes.byref(browseInfo))
|
||||
# OSError: exception: access violation writing 0x00007FFB582DC9BF
|
||||
if pidl:
|
||||
pidl = ctypes.cast(pidl, PIDLIST_ABSOLUTE)
|
||||
path = ctypes.create_unicode_buffer(MAX_PATH)
|
||||
ctypes.windll.shell32.SHGetPathFromIDListW(pidl, path)
|
||||
path = SHGetPathFromIDListW(pidl)
|
||||
ctypes.windll.ole32.CoTaskMemFree(pidl)
|
||||
directory = path.value
|
||||
else:
|
||||
|
Loading…
x
Reference in New Issue
Block a user