Skip to content

Commit c4eb3ad

Browse files
authored
gh-150836: Mount embedded Tk ZIP in _tkinter on Windows (GH-151562)
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.
1 parent 64fab74 commit c4eb3ad

4 files changed

Lines changed: 61 additions & 3 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make installed tkinter work with Tcl/Tk 9 builds that embed the Tk script library in the Tk DLL on Windows.

Modules/_tkinter.c

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ Copyright (C) 1994 Steen Lumholt.
5353
# include <tk.h>
5454
#endif
5555

56+
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
57+
# include <tkPlatDecls.h>
58+
#endif
59+
5660
#include "tkinter.h"
5761

5862
#if TK_HEX_VERSION < 0x0805020c
@@ -175,6 +179,57 @@ _get_tcl_lib_path(void)
175179
}
176180
#endif /* MS_WINDOWS */
177181

182+
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
183+
static void
184+
mount_tk_dll_zip(void)
185+
{
186+
HINSTANCE tk_module = Tk_GetHINSTANCE();
187+
wchar_t *tk_path = NULL;
188+
DWORD path_len = 0;
189+
for (DWORD buffer_len = 256;
190+
tk_path == NULL && buffer_len < (1024 * 1024);
191+
buffer_len *= 2)
192+
{
193+
tk_path = (wchar_t *)PyMem_RawMalloc(
194+
buffer_len * sizeof(*tk_path));
195+
if (tk_path != NULL) {
196+
path_len = GetModuleFileNameW(tk_module, tk_path, buffer_len);
197+
if (path_len == buffer_len) {
198+
PyMem_RawFree(tk_path);
199+
tk_path = NULL;
200+
}
201+
}
202+
}
203+
204+
if (tk_path == NULL || path_len == 0) {
205+
PyMem_RawFree(tk_path);
206+
return;
207+
}
208+
209+
Tcl_DString utf8_path;
210+
211+
Tcl_DStringInit(&utf8_path);
212+
Tcl_WCharToUtfDString(tk_path, path_len, &utf8_path);
213+
/* Failure is harmless if the DLL has no embedded ZIP or if another
214+
interpreter has already mounted it. */
215+
(void) TclZipfs_Mount(NULL, Tcl_DStringValue(&utf8_path),
216+
"//zipfs:/lib/tk", NULL);
217+
Tcl_DStringFree(&utf8_path);
218+
PyMem_RawFree(tk_path);
219+
}
220+
#endif
221+
222+
int
223+
Tkinter_TkInit(Tcl_Interp *interp)
224+
{
225+
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
226+
/* Tcl/Tk 9 may embed the tk_library in the Tk DLL which tcl_findLibrary
227+
does not search. Mount the DLL using Zipfs if possible. */
228+
mount_tk_dll_zip();
229+
#endif
230+
return Tk_Init(interp);
231+
}
232+
178233
/* The threading situation is complicated. Tcl is not thread-safe, except
179234
when configured with --enable-threads.
180235
@@ -544,7 +599,7 @@ Tcl_AppInit(Tcl_Interp *interp)
544599
return TCL_OK;
545600
}
546601

547-
if (Tk_Init(interp) == TCL_ERROR) {
602+
if (Tkinter_TkInit(interp) == TCL_ERROR) {
548603
PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
549604
return TCL_ERROR;
550605
}
@@ -2988,7 +3043,7 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self)
29883043
return NULL;
29893044
}
29903045
if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) {
2991-
if (Tk_Init(interp) == TCL_ERROR) {
3046+
if (Tkinter_TkInit(interp) == TCL_ERROR) {
29923047
Tkinter_Error(self);
29933048
return NULL;
29943049
}

Modules/tkappinit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Tcl_AppInit(Tcl_Interp *interp)
3737
return TCL_OK;
3838
}
3939

40-
if (Tk_Init(interp) == TCL_ERROR) {
40+
if (Tkinter_TkInit(interp) == TCL_ERROR) {
4141
return TCL_ERROR;
4242
}
4343

Modules/tkinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@
1616
(TK_RELEASE_LEVEL << 8) | \
1717
(TK_RELEASE_SERIAL << 0))
1818

19+
int Tkinter_TkInit(Tcl_Interp *interp);
20+
1921
#endif /* !TKINTER_H */

0 commit comments

Comments
 (0)