Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SetTimer(NULL,NULL,<timeout>,NULL) doesn't behave correctly. #1183

Closed
chentiangemalc opened this issue Aug 4, 2022 · 9 comments
Closed

SetTimer(NULL,NULL,<timeout>,NULL) doesn't behave correctly. #1183

chentiangemalc opened this issue Aug 4, 2022 · 9 comments

Comments

@chentiangemalc
Copy link

chentiangemalc commented Aug 4, 2022

When a hWnd is not specified to set timer, and it is checked in a peekmessage loop

  1. WM_TIMER seems to fire instantly, instead of after the time period has expired as per on Windows XP with NTVDM. i.e should be after 10 seconds in this example code.
  2. WM_TIMER doesn't fire again after clicking OK on message box in this test app, unless hit ALT+TAB. On Windows XP it will fire again on timer without needing to do this.

If a hwnd is specified, the WM_TIMER is correctly sent to the wndproc handler as expected.

Example code:

   SetTimer(NULL,NULL,10000,NULL);
   BOOL fRetVal = TRUE;
   
     // classic Win3.1 peek message loop   

     for(;;)
     {

        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {              
        
           if (msg.message == WM_TIMER)
           {   
           	MessageBox(hwnd,"Hit Timer","Timer!!",MB_OK);   
           }
           
           if (msg.message == WM_QUIT)
              return TRUE;

           TranslateMessage(&msg);
           DispatchMessage(&msg);
        }
        
        // check if need to do background processing, otherwise call WaitMessage
        WaitMessage(); 

     }

Environment (please complete the following information):
Windows 11 21H2 22000.739

Trace and sample program (MSVC 1.52 exe+source) attached
MSGTST.zip
trace.txt
.

@chentiangemalc chentiangemalc changed the title SetTimer(NULL,<timer>,NULL,NULL) doesn't behave correctly. SetTimer(NULL,NULL,<timeout>,NULL) doesn't behave correctly. Aug 4, 2022
@cracyc
Copy link
Contributor

cracyc commented Aug 4, 2022

This isn't a winevdm problem. Windows 10 and 11 ime creates timers in threads that have windows (Microsoft broke their own programs with this, #755). You need to check the timer id to get the correct message.

@chentiangemalc
Copy link
Author

I could kill off those timers with this code, although haven't fully investigated what kind of impacts it would have on the app, expect it may risk some IME functionality breaking.

void KillMsctfTimers()
{
	HWND hCurWnd = NULL;
	DWORD dwWindowProcessID;
	BOOL result;
	DWORD dwCurrentProcessID = GetCurrentProcessId();
	do
	{
		hCurWnd = FindWindowEx(NULL, hCurWnd, L"MSCTFIME UI", L"MSCTFIME UI");
		
		GetWindowThreadProcessId(hCurWnd, &dwWindowProcessID);
		if (dwCurrentProcessID == dwWindowProcessID)
		{
			result = KillTimer(hCurWnd, 1);
		}
	} while (hCurWnd != NULL);
}

@cracyc
Copy link
Contributor

cracyc commented Sep 1, 2022

The ime timers have a callback function so that pointer address can be checked in winevdm and if it's in a win32 dll the message can just be dispatched without ever being passed to the win16 program. In fact #778 already does that without checking though which is likely the problem in #1195. BTW do you have a trace from the program which depends on this (other than your test program).

@chentiangemalc
Copy link
Author

Here is full trace from original program. Essentially the application hangs with no errors when the issue occurs. I also included my output from WinDbg + WinXP checked build of NTVDM which shows some details when it works. Originally I thought it may have been the IME timer messages throwing off the application, but it seems the timer not firing at all is the more serious problem. The application behaves slightly better if
AppLogs.zip
SetTimer16 is modified to change hWnd = NULL to hWnd=GetActiveWindow16 ... but that also seems to trigger additional different behavior in my testing.

@otya128
Copy link
Owner

otya128 commented Sep 2, 2022

Timer callbacks set from 16-bit are always allocated in allocate_timer_thunk or null, so it is easy to determine if they are not null.

        if (msg.lParam && !is_timer_thunk((TIMERPROC)msg.lParam))
        {
            DispatchMessageA(&msg);
            return PeekMessage32_16(msg16, hwnd16, first, last, flags, wHaveParamHigh);
        }
BOOL is_timer_thunk(TIMERPROC proc)
{
    return timer_thunk_array <= proc && proc < timer_thunk_array + MAX_TIMER_THUNK;
}

@chentiangemalc
Copy link
Author

In this particular app it doesn’t specify a call back for timer it seems to just rely on WM_TIMER message and PeekMessage

@otya128
Copy link
Owner

otya128 commented Sep 2, 2022

I don't think the Win32 side needs to consider setting a timer with hWnd=NULL and lpTimerFunc=NULL, so that fix should be fine.

@cracyc
Copy link
Contributor

cracyc commented Sep 3, 2022

#1196 works fine with ms oceans, see if it works with your program.

@chentiangemalc
Copy link
Author

#1196 fixes my applications issue.

@otya128 otya128 closed this as completed Sep 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants