@@ -252,8 +252,119 @@ static PyMethodDef functions[] = {
252252 { NULL , NULL } /* sentinel */
253253};
254254
255- // Functions to fill global TCL / Tk function pointers from tkinter module.
255+ // Functions to fill global TCL / Tk function pointers by dynamic loading
256+ #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
256257
258+ /*
259+ * On Windows, we can't load the tkinter module to get the TCL or Tk symbols,
260+ * because Windows does not load symbols into the library name-space of
261+ * importing modules. So, knowing that tkinter has already been imported by
262+ * Python, we scan all modules in the running process for the TCL and Tk
263+ * function names.
264+ */
265+ #include < windows.h>
266+ #define PSAPI_VERSION 1
267+ #include < psapi.h>
268+ // Must be linked with 'psapi' library
269+
270+ FARPROC _dfunc (HMODULE lib_handle, const char *func_name)
271+ {
272+ // Load function `func_name` from `lib_handle`.
273+ // Set Python exception if we can't find `func_name` in `lib_handle`.
274+ // Returns function pointer or NULL if not present.
275+
276+ char message[100 ];
277+
278+ FARPROC func = GetProcAddress (lib_handle, func_name);
279+ if (func == NULL ) {
280+ sprintf (message, " Cannot load function %s" , func_name);
281+ PyErr_SetString (PyExc_RuntimeError, message);
282+ }
283+ return func;
284+ }
285+
286+ int get_tcl (HMODULE hMod)
287+ {
288+ // Try to fill TCL global vars with function pointers. Return 0 for no
289+ // functions found, 1 for all functions found, -1 for some but not all
290+ // functions found.
291+ TCL_CREATE_COMMAND = (tcl_cc) GetProcAddress (hMod, " Tcl_CreateCommand" );
292+ if (TCL_CREATE_COMMAND == NULL ) { // Maybe not TCL module
293+ return 0 ;
294+ }
295+ TCL_APPEND_RESULT = (tcl_app_res) _dfunc (hMod, " Tcl_AppendResult" );
296+ return (TCL_APPEND_RESULT == NULL ) ? -1 : 1 ;
297+ }
298+
299+ int get_tk (HMODULE hMod)
300+ {
301+ // Try to fill Tk global vars with function pointers. Return 0 for no
302+ // functions found, 1 for all functions found, -1 for some but not all
303+ // functions found.
304+ TK_MAIN_WINDOW = (tk_mw) GetProcAddress (hMod, " Tk_MainWindow" );
305+ if (TK_MAIN_WINDOW == NULL ) { // Maybe not Tk module
306+ return 0 ;
307+ }
308+ TK_FIND_PHOTO = (tk_fp) _dfunc (hMod, " Tk_FindPhoto" );
309+ TK_PHOTO_PUTBLOCK = (tk_ppb_nc) _dfunc (hMod,
310+ " Tk_PhotoPutBlock_NoComposite" );
311+ TK_PHOTO_BLANK = (tk_pb) _dfunc (hMod, " Tk_PhotoBlank" );
312+ return ((TK_FIND_PHOTO == NULL ) ||
313+ (TK_PHOTO_PUTBLOCK == NULL ) ||
314+ (TK_PHOTO_BLANK == NULL )) ? -1 : 1 ;
315+ }
316+
317+ int load_tkinter_funcs (void )
318+ {
319+ // Load TCL and Tk functions by searching all modules in current process.
320+ // Return 0 for success, non-zero for failure.
321+
322+ HMODULE hMods[1024 ];
323+ HANDLE hProcess;
324+ DWORD cbNeeded;
325+ unsigned int i;
326+ int found_tcl = 0 ;
327+ int found_tk = 0 ;
328+
329+ // Returns pseudo-handle that does not need to be closed
330+ hProcess = GetCurrentProcess ();
331+
332+ // Iterate through modules in this process looking for TCL / Tk names
333+ if (EnumProcessModules (hProcess, hMods, sizeof (hMods), &cbNeeded)) {
334+ for (i = 0 ; i < (cbNeeded / sizeof (HMODULE)); i++) {
335+ if (!found_tcl) {
336+ found_tcl = get_tcl (hMods[i]);
337+ if (found_tcl == -1 ) {
338+ return 1 ;
339+ }
340+ }
341+ if (!found_tk) {
342+ found_tk = get_tk (hMods[i]);
343+ if (found_tk == -1 ) {
344+ return 1 ;
345+ }
346+ }
347+ if (found_tcl && found_tk) {
348+ return 0 ;
349+ }
350+ }
351+ }
352+
353+ if (found_tcl == 0 ) {
354+ PyErr_SetString (PyExc_RuntimeError, " Could not find TCL routines" );
355+ } else {
356+ PyErr_SetString (PyExc_RuntimeError, " Could not find Tk routines" );
357+ }
358+ return 1 ;
359+ }
360+
361+ #else // not Windows
362+
363+ /*
364+ * On Unix, we can get the TCL and Tk synbols from the tkinter module, because
365+ * tkinter uses these symbols, and the symbols are therefore visible in the
366+ * tkinter dynamic library (module).
367+ */
257368#if PY3K
258369#define TKINTER_PKG " tkinter"
259370#define TKINTER_MOD " _tkinter"
@@ -273,31 +384,8 @@ char *fname2char(PyObject *fname)
273384#define fname2char (s ) (PyString_AsString(s))
274385#endif
275386
276- #if defined(_MSC_VER)
277- #include < windows.h>
278- #define LIB_PTR_TYPE HMODULE
279- #define LOAD_LIB (name ) LoadLibrary(name)
280- #define CLOSE_LIB (name ) FreeLibrary(name)
281- FARPROC _dfunc (LIB_PTR_TYPE lib_handle, const char *func_name)
282- {
283- // Load function `func_name` from `lib_handle`.
284- // Set Python exception if we can't find `func_name` in `lib_handle`.
285- // Returns function pointer or NULL if not present.
286-
287- char message[100 ];
288-
289- FARPROC func = GetProcAddress (lib_handle, func_name);
290- if (func == NULL ) {
291- sprintf (message, " Cannot load function %s" , func_name);
292- PyErr_SetString (PyExc_RuntimeError, message);
293- }
294- return func;
295- }
296- #else
297387#include < dlfcn.h>
298- #define LIB_PTR_TYPE void *
299- #define LOAD_LIB (name ) dlopen(name, RTLD_LAZY)
300- #define CLOSE_LIB (name ) dlclose(name)
388+
301389void *_dfunc (void *lib_handle, const char *func_name)
302390{
303391 // Load function `func_name` from `lib_handle`.
@@ -313,9 +401,8 @@ void *_dfunc(void *lib_handle, const char *func_name)
313401 }
314402 return func;
315403}
316- #endif
317404
318- int _func_loader (LIB_PTR_TYPE lib)
405+ int _func_loader (void * lib)
319406{
320407 // Fill global function pointers from dynamic lib.
321408 // Return 1 if any pointer is NULL, 0 otherwise.
@@ -339,7 +426,7 @@ int load_tkinter_funcs(void)
339426 // Load tkinter global funcs from tkinter compiled module.
340427 // Return 0 for success, non-zero for failure.
341428 int ret = -1 ;
342- LIB_PTR_TYPE tkinter_lib;
429+ void * tkinter_lib;
343430 char *tkinter_libname;
344431 PyObject *pModule = NULL , *pSubmodule = NULL , *pString = NULL ;
345432
@@ -359,21 +446,22 @@ int load_tkinter_funcs(void)
359446 if (tkinter_libname == NULL ) {
360447 goto exit;
361448 }
362- tkinter_lib = LOAD_LIB (tkinter_libname);
449+ tkinter_lib = dlopen (tkinter_libname, RTLD_LAZY );
363450 if (tkinter_lib == NULL ) {
364451 PyErr_SetString (PyExc_RuntimeError,
365452 " Cannot dlopen tkinter module file" );
366453 goto exit;
367454 }
368455 ret = _func_loader (tkinter_lib);
369456 // dlclose probably safe because tkinter has been imported.
370- CLOSE_LIB (tkinter_lib);
457+ dlclose (tkinter_lib);
371458exit:
372459 Py_XDECREF (pModule);
373460 Py_XDECREF (pSubmodule);
374461 Py_XDECREF (pString);
375462 return ret;
376463}
464+ #endif // end not Windows
377465
378466#if PY3K
379467static PyModuleDef _tkagg_module = { PyModuleDef_HEAD_INIT, " _tkagg" , " " , -1 , functions,
0 commit comments