From ee1df33cec16b9baaf657cc3520eeded33c7dbad Mon Sep 17 00:00:00 2001 From: Athanasius Date: Thu, 17 Nov 2022 15:45:18 +0000 Subject: [PATCH 01/12] TEMPORARY: Ignore venv-3.11_64 in LANG comment hook --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5b534279..f7f16901 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -82,7 +82,7 @@ repos: - id: LANG_comments name: 'LANG comments' language: system - entry: python scripts/find_localised_strings.py --compare-lang L10n/en.template --directory . --ignore coriolis-data --ignore dist.win32 + entry: python scripts/find_localised_strings.py --compare-lang L10n/en.template --directory . --ignore coriolis-data --ignore dist.win32 --ignore venv-3.11_64 pass_filenames: false always_run: true From f141fccd86ded08e503fb45463cd7d35d139a0f2 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Thu, 17 Nov 2022 17:39:09 +0000 Subject: [PATCH 02/12] protocol.py: Change definition of DefWindowProcW to work on 64-bit Given this is the form of definition in the official Python docs I'm wondering if this only ever worked on 32-bit by accident. So, it was nothing to do with the type needing to be changed for 64-bit. The error: ctypes.ArgumentError: argument 4: : int too long to convert was a red herring in those terms. --- protocol.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/protocol.py b/protocol.py index 290a7031..eddc6391 100644 --- a/protocol.py +++ b/protocol.py @@ -106,12 +106,12 @@ if sys.platform == 'darwin' and getattr(sys, 'frozen', False): # noqa: C901 # i def handleEvent_withReplyEvent_(self, event, replyEvent) -> None: # noqa: N802 N803 # Required to override """Actual event handling from NSAppleEventManager.""" - protocolhandler.lasturl = urllib.parse.unquote( # noqa: F821: type: ignore # Its going to be a DPH in + protocolhandler.lasturl = urllib.parse.unquote( # noqa: F821: type: ignore # It's going to be a DPH in # this code event.paramDescriptorForKeyword_(keyDirectObject).stringValue() ).strip() - protocolhandler.master.after(DarwinProtocolHandler.POLL, protocolhandler.poll) # noqa: F821: type: ignore + protocolhandler.master.after(DarwinProtocolHandler.POLL, protocolhandler.poll) # noqa: F821 # type: ignore elif (config.auth_force_edmc_protocol @@ -157,7 +157,13 @@ elif (config.auth_force_edmc_protocol CreateWindowExW.restype = HWND RegisterClassW = windll.user32.RegisterClassW RegisterClassW.argtypes = [POINTER(WNDCLASS)] - DefWindowProcW = windll.user32.DefWindowProcW + # DefWindowProcW + # Ref: + # LRESULT DefWindowProcW([in] HWND hWnd,[in] UINT Msg,[in] WPARAM wParam,[in] LPARAM lParam); + # As per example at + prototype = WINFUNCTYPE(c_long, HWND, UINT, WPARAM, LPARAM) + paramflags = (1, "hWnd"), (1, "Msg"), (1, "wParam"), (1, "lParam") + DefWindowProcW = prototype(("DefWindowProcW", windll.user32), paramflags) GetParent = windll.user32.GetParent SetForegroundWindow = windll.user32.SetForegroundWindow From da530f135e4181d473cc5e72e51e4c52ee079bca Mon Sep 17 00:00:00 2001 From: Athanasius Date: Thu, 17 Nov 2022 20:52:25 +0000 Subject: [PATCH 03/12] 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
`. 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'). --- prefs.py | 81 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 11 deletions(-) diff --git a/prefs.py b/prefs.py index e5ab242b..e4964785 100644 --- a/prefs.py +++ b/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 + 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: + BrowseCallbackProc = WINFUNCTYPE(ctypes.c_int, HWND, ctypes.c_uint, LPARAM, LPARAM) + + class BROWSEINFOW(ctypes.Structure): + """ + Windows file browser fields. + + Ref: + """ + + _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: + # 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: + # 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: : 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: From 09ecdbb8495b3a79e70d03d41a2b15fc81aac994 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 18 Nov 2022 10:47:11 +0000 Subject: [PATCH 04/12] prefs.py: Always use `tkinter.filedialog` for Output File Location * I can't even get this code to be problematic, with a folder containing unicode heart characters, on 64-bit Python 3.7.9 (Release/4.1.6 adjusted to not set UTF-8 locale), let alone on 64-bit Python 3.11 and this branch. So, just always use the tkinter dialog. Bye-bye ctypes code which I just couldn't get to work under 64-bit Python. * I *think* the issue with the ctypes code was that under 32-bit an 'int' and a pointer are the same size. 'Raw' (not declaring types beforehand) the `SHBrowseForFolderW()` function causes ctypes to consider it returns an int. This works on 32-bit. But on 64-bit that int is still 32-bits, but pointers are 64-bit, so ctypes ends up coercing/casting/truncating the returned pointer into an int, which than can't even be cast back to a pointer. Meanwhile, attempting to properly define the signature of the function has only lead to it crashing on invocation, despite being passed the same BROWSEINFOW structure, defined in the same manner. This might be a matter of a type within it needing adjusting, but I was following the docs there. --- prefs.py | 49 +++++++------------------------------------------ 1 file changed, 7 insertions(+), 42 deletions(-) diff --git a/prefs.py b/prefs.py index e4964785..6683f297 100644 --- a/prefs.py +++ b/prefs.py @@ -1078,48 +1078,13 @@ class PreferencesDialog(tk.Toplevel): :param title: Title of the window :param pathvar: the path to start the dialog on """ - import locale - - # If encoding isn't UTF-8 we can't use the tkinter dialog - current_locale = locale.getlocale(locale.LC_CTYPE) - directory = None - if sys.platform == 'win32' and current_locale[1] not in ('utf8', 'UTF8', 'utf-8', 'UTF-8'): - def browsecallback(hwnd, uMsg, lParam, lpData): # noqa: N803 # Windows API convention - # set initial folder - if uMsg == BFFM_INITIALIZED and lpData: - ctypes.windll.user32.SendMessageW(hwnd, BFFM_SETSELECTION, 1, lpData) - return 0 - - 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() - ctypes.windll.ole32.CoInitialize(None) - pidl = ctypes.windll.shell32.SHBrowseForFolderW(ctypes.byref(browseInfo)) - # ctypes.ArgumentError: argument 1: : 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) - path = SHGetPathFromIDListW(pidl) - ctypes.windll.ole32.CoTaskMemFree(pidl) - directory = path.value - else: - directory = None - - else: - import tkinter.filedialog - directory = tkinter.filedialog.askdirectory( - parent=self, - initialdir=expanduser(pathvar.get()), - title=title, - mustexist=tk.TRUE - ) + import tkinter.filedialog + directory = tkinter.filedialog.askdirectory( + parent=self, + initialdir=expanduser(pathvar.get()), + title=title, + mustexist=tk.TRUE + ) if directory: pathvar.set(directory) From 12b77f696b2290e7efb383842a535dfa6175f03e Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 18 Nov 2022 11:25:22 +0000 Subject: [PATCH 05/12] prefs.py: Remove the now un-used ctypes imports/definitions --- prefs.py | 68 +------------------------------------------------------- 1 file changed, 1 insertion(+), 67 deletions(-) diff --git a/prefs.py b/prefs.py index 6683f297..8b372683 100644 --- a/prefs.py +++ b/prefs.py @@ -181,10 +181,7 @@ if sys.platform == 'darwin': elif sys.platform == 'win32': import ctypes import winreg - from ctypes import POINTER, WINFUNCTYPE, Structure - from ctypes.wintypes import ( - BOOL, BYTE, HINSTANCE, HWND, LPARAM, LPCWSTR, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT, USHORT - ) + from ctypes.wintypes import HINSTANCE, HWND, LPCWSTR, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT is_wine = False try: WINE_REGISTRY_KEY = r'HKEY_LOCAL_MACHINE\Software\Wine' @@ -195,69 +192,6 @@ elif sys.platform == 'win32': except OSError: pass - ########################################################################### - # From - 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: - BrowseCallbackProc = WINFUNCTYPE(ctypes.c_int, HWND, ctypes.c_uint, LPARAM, LPARAM) - - class BROWSEINFOW(ctypes.Structure): - """ - Windows file browser fields. - - Ref: - """ - - _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 - # SHGetPathFromIDListW - # Ref: - # 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) - - # SHBrowseForFolderW - # Ref: - # 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: try: From f9d384cc6dfcc32a6fd0ddd28a468a92dc52072a Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 18 Nov 2022 11:32:25 +0000 Subject: [PATCH 06/12] prefs.py: Comment why `except OSError` being thrown away (wine check) --- prefs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prefs.py b/prefs.py index 8b372683..91123350 100644 --- a/prefs.py +++ b/prefs.py @@ -189,7 +189,7 @@ elif sys.platform == 'win32': winreg.OpenKey(reg, WINE_REGISTRY_KEY) is_wine = True - except OSError: + except OSError: # Assumed to be 'path not found', i.e. not-wine pass CalculatePopupWindowPosition = None From cdb61bcced1fb9cd31414310071df584e71b599f Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 18 Nov 2022 12:39:32 +0000 Subject: [PATCH 07/12] stats.py: Checking CAPI lastStarport is un-necessary, as never used. The `lastSystem` *is* however used, for the 'current ship not currently docked' case. --- stats.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/stats.py b/stats.py index 6b5d8d61..d690dce6 100644 --- a/stats.py +++ b/stats.py @@ -335,8 +335,6 @@ class StatsDialog(): elif ( not capi_data.get('lastSystem') or not capi_data['lastSystem'].get('name', '').strip() - or not capi_data.get('lastStarport') - or not capi_data['lastStarport'].get('name', '').strip() ): # Shouldn't happen # LANG: Unknown location From 3a8f3d62978edf0c3d24a01aa11fc4911bc73656 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 18 Nov 2022 15:31:07 +0000 Subject: [PATCH 08/12] Build: Switch to requiring 64-bit, not 32-bit, Python --- Build-exe-and-msi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build-exe-and-msi.py b/Build-exe-and-msi.py index adc04432..516ac21f 100644 --- a/Build-exe-and-msi.py +++ b/Build-exe-and-msi.py @@ -22,7 +22,7 @@ if sys.version_info[0:2] != (3, 11): raise AssertionError(f'Unexpected python version {sys.version}') if sys.platform == 'win32': - assert platform.architecture()[0] == '32bit', 'A Python 32bit build is required' + assert platform.architecture()[0] == '64bit', 'A Python 64bit build is required' import py2exe # noqa: F401 # Yes, this *is* used dist_dir = 'dist.win32' From b678985fa6c9c61a35409c3b4c9021ea996bca8e Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 18 Nov 2022 16:12:00 +0000 Subject: [PATCH 09/12] github: windows-build: Use x64 versions of WinSparkle files --- .github/workflows/windows-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index dc0fc120..93091a7c 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -34,7 +34,7 @@ jobs: run: | Invoke-Webrequest -UseBasicParsing https://github.com/vslavik/winsparkle/releases/download/v0.7.0/WinSparkle-0.7.0.zip -OutFile out.zip Expand-Archive out.zip - Move-Item 'out\WinSparkle-0.7.0\Release\*' '.\' + Move-Item 'out\WinSparkle-0.7.0\x64\Release\*' '.\' - name: Build EDMC run: | From 7620bcdaaad375a724e5ab6651d6fcca41be367b Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 18 Nov 2022 16:14:05 +0000 Subject: [PATCH 10/12] Revert "TEMPORARY: Ignore venv-3.11_64 in LANG comment hook" This reverts commit af785457edd0bc8139941157eeb1d2937a89899d. --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f7f16901..5b534279 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -82,7 +82,7 @@ repos: - id: LANG_comments name: 'LANG comments' language: system - entry: python scripts/find_localised_strings.py --compare-lang L10n/en.template --directory . --ignore coriolis-data --ignore dist.win32 --ignore venv-3.11_64 + entry: python scripts/find_localised_strings.py --compare-lang L10n/en.template --directory . --ignore coriolis-data --ignore dist.win32 pass_filenames: false always_run: true From 08d28c6f3d5ad8ff0447dd22877ce330bbb97742 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 23 Dec 2022 16:41:07 +0000 Subject: [PATCH 11/12] protocol: Properly prototype GetMessageW & comment about 'exception' * In trying to fix the return type 'exception' I first decided to properly prototype GetMessageW(). * But it turns out that you just can't get rid of that exception, so I just added a comment about it being harmless, because the functionality works as intended anyway. --- protocol.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/protocol.py b/protocol.py index eddc6391..0ce3bd76 100644 --- a/protocol.py +++ b/protocol.py @@ -125,8 +125,8 @@ elif (config.auth_force_edmc_protocol from ctypes import windll # type: ignore from ctypes import POINTER, WINFUNCTYPE, Structure, byref, c_long, c_void_p, create_unicode_buffer, wstring_at from ctypes.wintypes import ( - ATOM, BOOL, DWORD, HBRUSH, HGLOBAL, HICON, HINSTANCE, HMENU, HWND, INT, LPARAM, LPCWSTR, LPVOID, LPWSTR, MSG, - UINT, WPARAM + ATOM, BOOL, DWORD, HBRUSH, HGLOBAL, HICON, HINSTANCE, HMENU, HWND, INT, LPARAM, LPCWSTR, LPMSG, LPVOID, LPWSTR, + MSG, UINT, WPARAM ) class WNDCLASS(Structure): @@ -161,13 +161,21 @@ elif (config.auth_force_edmc_protocol # Ref: # LRESULT DefWindowProcW([in] HWND hWnd,[in] UINT Msg,[in] WPARAM wParam,[in] LPARAM lParam); # As per example at + prototype = WINFUNCTYPE(c_long, HWND, UINT, WPARAM, LPARAM) paramflags = (1, "hWnd"), (1, "Msg"), (1, "wParam"), (1, "lParam") DefWindowProcW = prototype(("DefWindowProcW", windll.user32), paramflags) + GetParent = windll.user32.GetParent SetForegroundWindow = windll.user32.SetForegroundWindow - GetMessageW = windll.user32.GetMessageW + # + # NB: Despite 'BOOL' return type, it *can* be >0, 0 or -1, so is actually + # c_long + prototype = WINFUNCTYPE(c_long, LPMSG, HWND, UINT, UINT) + paramflags = (1, "lpMsg"), (1, "hWnd"), (1, "wMsgFilterMin"), (1, "wMsgFilterMax") + GetMessageW = prototype(("GetMessageW", windll.user32), paramflags) + TranslateMessage = windll.user32.TranslateMessage DispatchMessageW = windll.user32.DispatchMessageW PostThreadMessageW = windll.user32.PostThreadMessageW @@ -309,6 +317,17 @@ elif (config.auth_force_edmc_protocol msg = MSG() # Calls GetMessageW: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessagew + # Something is off with the return from this, meaning you'll see: + # Exception ignored on converting result of ctypes callback function: + # Traceback (most recent call last): + # File "C:\Users\Athan\Documents\Devel\EDMarketConnector\protocol.py", line 323, in worker + # while int(GetMessageW(byref(msg), None, 0, 0)) != 0: + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + # TypeError: 'c_long' object cannot be interpreted as an integer + # + # But it does actually work. Either getting a non-0 value and + # entering the loop, or getting 0 and exiting it. while GetMessageW(byref(msg), None, 0, 0) != 0: logger.trace_if('frontier-auth.windows', f'DDE message of type: {msg.message}') if msg.message == WM_DDE_EXECUTE: From ec90912d3143e307de173ada01bcdee4aecb9de7 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Fri, 23 Dec 2022 17:34:58 +0000 Subject: [PATCH 12/12] Build: Don't enforce any bit-ness of platform Testing shows this branch works (after build) on both 32-bit and 64-bit. --- Build-exe-and-msi.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Build-exe-and-msi.py b/Build-exe-and-msi.py index 516ac21f..ee157fdf 100644 --- a/Build-exe-and-msi.py +++ b/Build-exe-and-msi.py @@ -2,7 +2,6 @@ """Build to executables and MSI installer using py2exe and other tools.""" import os import pathlib -import platform import re import shutil import sys @@ -22,7 +21,6 @@ if sys.version_info[0:2] != (3, 11): raise AssertionError(f'Unexpected python version {sys.version}') if sys.platform == 'win32': - assert platform.architecture()[0] == '64bit', 'A Python 64bit build is required' import py2exe # noqa: F401 # Yes, this *is* used dist_dir = 'dist.win32'