- labels: 104347 --> 13. Win Menus
OriginalBugID: 3921 Bug
Version: 8.2.2
SubmitDate: '1999-12-22'
LastModified: '2000-01-25'
Severity: SER
Status: UnAssn
Submitter: techsupp
ChangedBy: hobbs
OS: Windows NT
OSVersion: NT4.0 ServicePack6
Machine: intel PC
Name:
Dr. Lukas Rosenthaler
Extensions:
img1.2, incr tcl
CustomShell:
with exception of patch above no other
Comments:
The cause of the problem is as follows:
The window for the popup menu is initialized in TkpMenuInit. The window handle is stored in a
thread specific data area (using Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); ).
If the thread exits, the thread specific data is lost, and so the popup menu's window handle. However,
starting a new thread doesn't invoke TkpMenuInit anymore. Then the WIN32-function
TrackPopupMenu (called from within TkpPostMenu) receives an invalid window handle and
returns immediately (The new, patched version will check the return value of TrackPopupMenu
and issue an error, if something's wrong).
Solution to the Problem:
The code to create the popup menu's window has been moved to TkpMenuThreadInit. Within
TkpMenuThreadInit, an exit-handler using "Tcl_CreateThreadExitHandler(MenuExitHandler,
(ClientData) NULL);" has been added to destroy the menu-window if the thread exits.
Tests (all compiled with "/DTCL_THREADS=1" !) have shown no side-effects of this patch.
ReproducibleScript:
Embedded Tcl/Tk in a threaded environment. The application (using it's own non-tcl windows based
event loop) launches Tcl/Tk-threads which have their own toplevel windows and own event loops.
ObservedBehavior:
When using threads, the popup of menus doesn't work properly. The first time a thread is invoked,
popup menus work fine, but if the first thread exits using Tcl_ThreadExit (0), and later a second thread
is invoked, then the popup menus don't work anymore.
DesiredBehavior:
popup menu should work properly...
Patch:
*** tkWinMenu-orig.c Wed Sep 22 08:53:24 1999
--- tkWinMenu.c Wed Dec 22 11:54:24 1999
***************
*** 778,785 ****
}
}
! TrackPopupMenu(winMenuHdl, flags, x, y, 0,
! tsdPtr->menuHWND, &noGoawayRect);
Tcl_SetServiceMode(oldServiceMode);
GetCursorPos(&point);
--- 778,794 ----
}
}
! if (TrackPopupMenu(winMenuHdl, flags, x, y, 0,
! tsdPtr->menuHWND, &noGoawayRect) == 0) {
! LPVOID lpMsgBuf;
! char errstr[1024];
! FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
! NULL, GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
! (LPTSTR) &lpMsgBuf, 0, NULL);
! sprintf (errstr, "[%s: #%04d] ERROR: TrackPopupMenu failed!\n%s",
! __FILE__, __LINE__, (char *) lpMsgBuf);
! MessageBox (NULL, errstr, "Tk Internal Error", MB_OK | MB_ICONERROR);
! }
Tcl_SetServiceMode(oldServiceMode);
GetCursorPos(&point);
***************
*** 2789,2814 ****
void
TkpMenuInit()
{
- WNDCLASS wndClass;
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- wndClass.style = CS_OWNDC;
- wndClass.lpfnWndProc = TkWinMenuProc;
- wndClass.cbClsExtra = 0;
- wndClass.cbWndExtra = 0;
- wndClass.hInstance = Tk_GetHINSTANCE();
- wndClass.hIcon = NULL;
- wndClass.hCursor = NULL;
- wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
- wndClass.lpszMenuName = NULL;
- wndClass.lpszClassName = MENU_CLASS_NAME;
- RegisterClass(&wndClass);
-
- tsdPtr->menuHWND = CreateWindow(MENU_CLASS_NAME, "MenuWindow", WS_POPUP,
- 0, 0, 10, 10, NULL, NULL, Tk_GetHINSTANCE(), NULL);
-
- Tcl_CreateExitHandler(MenuExitHandler, (ClientData) NULL);
SetDefaults(1);
}
--- 2798,2804 ----
***************
*** 2831,2838 ****
--- 2821,2848 ----
void
TkpMenuThreadInit()
{
+ WNDCLASS wndClass;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+
+ wndClass.style = CS_OWNDC;
+ wndClass.lpfnWndProc = TkWinMenuProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = Tk_GetHINSTANCE();
+ wndClass.hIcon = NULL;
+ wndClass.hCursor = NULL;
+ wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wndClass.lpszMenuName = NULL;
+ wndClass.lpszClassName = MENU_CLASS_NAME;
+ RegisterClass(&wndClass);
+
+ tsdPtr->menuHWND = CreateWindow(MENU_CLASS_NAME, "MenuWindow", WS_POPUP,
+ 0, 0, 10, 10, NULL, NULL, Tk_GetHINSTANCE(), NULL);
+
+ Tcl_CreateThreadExitHandler(MenuExitHandler, (ClientData) NULL);
+ SetDefaults(0);
Tcl_InitHashTable(&tsdPtr->winMenuTable, TCL_ONE_WORD_KEYS);
Tcl_InitHashTable(&tsdPtr->commandTable, TCL_ONE_WORD_KEYS);
PatchFiles:
tkWinMenu.c