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: | diff --git a/Build-exe-and-msi.py b/Build-exe-and-msi.py index 71e1eace..33f95a5b 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] == '32bit', 'A Python 32bit build is required' import py2exe # noqa: F401 # Yes, this *is* used dist_dir = 'dist.win32' diff --git a/prefs.py b/prefs.py index a356848b..48d04975 100644 --- a/prefs.py +++ b/prefs.py @@ -181,7 +181,7 @@ 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.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' @@ -189,22 +189,9 @@ 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 - # 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) - - 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)] - CalculatePopupWindowPosition = None if not is_wine: try: @@ -1044,42 +1031,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 = BROWSEINFO() # noqa: N806 # Windows convention - 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)) - if pidl: - path = ctypes.create_unicode_buffer(MAX_PATH) - ctypes.windll.shell32.SHGetPathFromIDListW(pidl, path) - 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) diff --git a/protocol.py b/protocol.py index f0e1b4a8..cf3a9f75 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 @@ -129,8 +129,8 @@ elif (config.auth_force_edmc_protocol 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,11 +161,25 @@ 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 - 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 @@ -307,6 +321,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: 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