Menu

#890 Popup-menus may fail if using threads

obsolete: 8.2.2
open
5
2003-11-12
2000-11-01
No

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

Discussion

  • Donal K. Fellows

    • labels: 104347 --> 13. Win Menus
     
  • Don Porter

    Don Porter - 2003-11-12
    • assigned_to: nobody --> hobbs
     
MongoDB Logo MongoDB