From 6b57a35c56598eea37bf96b2746a2a94a9b116f8 Mon Sep 17 00:00:00 2001 From: "Jonathan J. Helmus" Date: Tue, 16 Jun 2026 16:00:37 -0500 Subject: [PATCH 1/3] gh-150836: Mount embedded Tk ZIP in _tkinter on Windows Tcl/Tk 9 may embed the Tk script library in the Tk DLL on Windows. This embedded library is not found by Tcl by default. Mount the loaded Tk DLL as a zipfs archive before calling Tk_Init(), so Tk can find its embedded tk_library using its existing library discovery logic. Preserve Tk_Init()'s normal path if the library is not embedded. --- ...-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst | 1 + Modules/_tkinter.c | 41 ++++++++++++++++++- Modules/tkappinit.c | 2 +- Modules/tkinter.h | 2 + 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst diff --git a/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst b/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst new file mode 100644 index 00000000000000..6497b7927db7da --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst @@ -0,0 +1 @@ +Make installed tkinter work with Tcl/Tk 9 builds that embed the Tk script library in the Tk DLL on Windows. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 6eca98a3c8033f..288424cc843c11 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -53,6 +53,10 @@ Copyright (C) 1994 Steen Lumholt. # include #endif +#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9 +# include +#endif + #include "tkinter.h" #if TK_HEX_VERSION < 0x0805020c @@ -175,6 +179,39 @@ _get_tcl_lib_path(void) } #endif /* MS_WINDOWS */ +#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9 +static void +mount_tk_dll_zip(void) +{ + HINSTANCE tk_module = Tk_GetHINSTANCE(); + wchar_t tk_path[MAX_PATH]; + DWORD path_len = GetModuleFileNameW(tk_module, tk_path, MAX_PATH); + + if (path_len == 0 || path_len >= MAX_PATH) { + return; + } + + Tcl_DString utf8_path; + + Tcl_DStringInit(&utf8_path); + Tcl_WCharToUtfDString(tk_path, path_len, &utf8_path); + (void) TclZipfs_Mount(NULL, Tcl_DStringValue(&utf8_path), + "//zipfs:/lib/tk", NULL); + Tcl_DStringFree(&utf8_path); +} +#endif + +int +Tkinter_TkInit(Tcl_Interp *interp) +{ +#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9 + /* Tcl/Tk 9 may embed the tk_library in the Tk DLL which tcl_findLibrary + does not search. Mount the DLL using Zipfs if possible. */ + mount_tk_dll_zip(); +#endif + return Tk_Init(interp); +} + /* The threading situation is complicated. Tcl is not thread-safe, except when configured with --enable-threads. @@ -544,7 +581,7 @@ Tcl_AppInit(Tcl_Interp *interp) return TCL_OK; } - if (Tk_Init(interp) == TCL_ERROR) { + if (Tkinter_TkInit(interp) == TCL_ERROR) { PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp)); return TCL_ERROR; } @@ -2988,7 +3025,7 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self) return NULL; } if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) { - if (Tk_Init(interp) == TCL_ERROR) { + if (Tkinter_TkInit(interp) == TCL_ERROR) { Tkinter_Error(self); return NULL; } diff --git a/Modules/tkappinit.c b/Modules/tkappinit.c index 4c4081e43a8e3d..1075ccf24d4487 100644 --- a/Modules/tkappinit.c +++ b/Modules/tkappinit.c @@ -37,7 +37,7 @@ Tcl_AppInit(Tcl_Interp *interp) return TCL_OK; } - if (Tk_Init(interp) == TCL_ERROR) { + if (Tkinter_TkInit(interp) == TCL_ERROR) { return TCL_ERROR; } diff --git a/Modules/tkinter.h b/Modules/tkinter.h index 40281c21760331..b73e99b28a4021 100644 --- a/Modules/tkinter.h +++ b/Modules/tkinter.h @@ -16,4 +16,6 @@ (TK_RELEASE_LEVEL << 8) | \ (TK_RELEASE_SERIAL << 0)) +int Tkinter_TkInit(Tcl_Interp *interp); + #endif /* !TKINTER_H */ From baaa53412b7c2e9bfaed6d6ed747d13dc2bef16e Mon Sep 17 00:00:00 2001 From: "Jonathan J. Helmus" Date: Thu, 18 Jun 2026 14:15:07 -0500 Subject: [PATCH 2/3] Support long paths when mounting the embedded Tk ZIP --- Modules/_tkinter.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 288424cc843c11..02e8cb92d12081 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -184,10 +184,25 @@ static void mount_tk_dll_zip(void) { HINSTANCE tk_module = Tk_GetHINSTANCE(); - wchar_t tk_path[MAX_PATH]; - DWORD path_len = GetModuleFileNameW(tk_module, tk_path, MAX_PATH); + wchar_t *tk_path = NULL; + DWORD path_len = 0; + for (DWORD buffer_len = 256; + tk_path == NULL && buffer_len < (1024 * 1024); + buffer_len *= 2) + { + tk_path = (wchar_t *)PyMem_RawMalloc( + buffer_len * sizeof(*tk_path)); + if (tk_path != NULL) { + path_len = GetModuleFileNameW(tk_module, tk_path, buffer_len); + if (path_len == buffer_len) { + PyMem_RawFree(tk_path); + tk_path = NULL; + } + } + } - if (path_len == 0 || path_len >= MAX_PATH) { + if (tk_path == NULL || path_len == 0) { + PyMem_RawFree(tk_path); return; } @@ -198,6 +213,7 @@ mount_tk_dll_zip(void) (void) TclZipfs_Mount(NULL, Tcl_DStringValue(&utf8_path), "//zipfs:/lib/tk", NULL); Tcl_DStringFree(&utf8_path); + PyMem_RawFree(tk_path); } #endif From 0c268a6ec305ee9a4f5a1fdc0bd03ec34e3dc83a Mon Sep 17 00:00:00 2001 From: "Jonathan J. Helmus" Date: Thu, 18 Jun 2026 14:25:39 -0500 Subject: [PATCH 3/3] Clarify expected Tk ZIP mount failures --- Modules/_tkinter.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 02e8cb92d12081..1deff4ed44684c 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -210,6 +210,8 @@ mount_tk_dll_zip(void) Tcl_DStringInit(&utf8_path); Tcl_WCharToUtfDString(tk_path, path_len, &utf8_path); + /* Failure is harmless if the DLL has no embedded ZIP or if another + interpreter has already mounted it. */ (void) TclZipfs_Mount(NULL, Tcl_DStringValue(&utf8_path), "//zipfs:/lib/tk", NULL); Tcl_DStringFree(&utf8_path);