Solved

KillTimer doesn't work.

Posted on 2009-05-04
15
1,362 Views
Last Modified: 2013-12-14
Hi, I am working with SetTimer and KillTimer a lot, and this is the first time that I encunter this problem.

I have a code inside Hook (SetWindowsHook) DLL.
I am doing
g_timer1=::SetTimer(NULL,1,200,gTimer1);
and the first command in in the timer I do:
void CALLBACK gTimer1(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
      ::KillTimer(0,g_timer1);
}
But the timer continue to work (is not killed).
0
Comment
Question by:VapiSoft
  • 5
  • 3
  • 3
  • +2
15 Comments
 
LVL 30

Accepted Solution

by:
Zoppo earned 200 total points
ID: 24294708
Hi VapiSoft,

you should check the return value - if it's FALSE use GetLastError to retrieve a windows error code which might help to find the problem.

ZOPPO
0
 
LVL 44

Assisted Solution

by:AndyAinscow
AndyAinscow earned 100 total points
ID: 24294769
From help files -
The KillTimer function does not remove WM_TIMER messages  already posted to the message queue.
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 100 total points
ID: 24296200
If that is a global hook - are you sure you are doing that in the right process' context?
0
 

Author Comment

by:VapiSoft
ID: 24296262
To ikr = I don't understand. If do: SetTimer, than the timer proc will be called in the same process context.
How can it be another process??
To Zoppo: It is running in a client's computer so I will check it tomorrow and let you know if and what is the error that it returns.
To AndyAinscow: The problem is not the last WM_TIME but that it continues forever.
0
 
LVL 86

Expert Comment

by:jkr
ID: 24296589
Well, if it is a global hook, it will be executed in a lot of processes, so you need to make sure that set and remove your timer in the same process.
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 100 total points
ID: 24296652
>>>> ::KillTimer(0,g_timer1);


That is a wrong call. The first argument is the hwnd of the window that runs the message queue. It actually shouldn't be NULL but the window handle of that window that installed the timer to its message queue. The second argument should be an ID in case you were using more than one timer. The g_timer1 is a pointer which actually was a bad event ID but might work nevertheless ... if you had provided the same ID with SetTimer. But there the event ID was 1 (what could work but surely is not a good choice for a timer installed by a hook).
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24296943
FYI: timers installed by SetTimer are not very accurate cause they were only evaluated at idle times from message bump. A timer installed by a hook has the disadvantage that you probably have difficulties to find out whether the current window you were hooked in, actually runs the main message loop, or only belongs to a modal dialog window, e. g. by a message box currently opened. In the latter case all timer actions may address the wrong target.

You better create a thread with the timer function as thread function and which was waiting 200 milliseconds before running:

void timerThread(void * par)
{
    Sleep(200);

     // if coming here about 200 msec were gone
     dowhatmustbedone(par);

}

The above is a one-time timer which is not dependent on message loops and window processing. you would call it like

  HANDLE hdl = _beginthread(timerThread, 0, this);

and the only thing to care for is that the pointer passed lives longer than the thread.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 30

Assisted Solution

by:Zoppo
Zoppo earned 200 total points
ID: 24302349
@itsmeandnobodyelse - I'm not sure if you're statement is correct:
> The first argument is the hwnd of the window that runs the message queue. It actually shouldn't be NULL ...

In MSDN for '::SetTimer' it's tells that 'If the function succeeds and the hWnd parameter is NULL, the return value is an integer identifying the new timer. An application can pass this value to the KillTimer function to destroy the timer.' and 'If the hWnd parameter is NULL, and the nIDEvent does not match an existing timer then it is ignored and a new timer ID is generated.'

ZOPPO
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24302433
The main error is that the second argument in KillTimer isn't the eventId you passed with the SetTimer.

The hwnd argument may work with NULL as well but I wouldn't do it with NULL cause the hwnd determines the message queue where the timer is handled. Especially in a hook you shouldn't have a problem to pass the window handle of the current window you were hooked in.
0
 
LVL 30

Expert Comment

by:Zoppo
ID: 24302469
Sorry, I still don't agree: In MSDN for '::KillTimer' you can find 'If the application calls SetTimer with hWnd set to NULL, this parameter must be the timer identifier returned by SetTimer.'

As far as I understand this you can either pass a none-NULL HWND to SetTimer or pass NULL as HWND and a pointer to a TimerProc-callback function as fourth parameter. In the first case WM_TIMER messages are sent to the passed window, in the other case the callback function is called.

So I can't see an error there.

@VapiSoft: Unfortunateley I have absoluteley no experience in using timers within hooks. But could you explain a little bit more detailed what kind of hook it is, if it's a global hook or a process-local hook. Is the SetTimer called outside or within the hook-procedure? Could it be that even the SetTimer is called continuously?

ZOPPO
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 24302501
@itsmeandnobodyelse.
Note there is a
gtimer1 - function
and
g_timer1 - variable
being used.  I think you missed the underscore
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24302619
>>>> If the function succeeds and the hWnd parameter is NULL, the return value is an integer identifying the new timer

You are right. The docs do describe the way you coded. But I doubt that it could work in your case as the main condition for a timer created by SetTimer is the existence of a message queue. If no window is associated with the timer you would need to run the message pump from your thread. Look at the Remarks section of the MSDN article which says

------------------------
... When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.
------------------------







0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24303420
>>>> I think you missed the underscore
Yes, I didn't read the code thoroughly.

>>>> g_timer1=::SetTimer(NULL,1,200,gTimer1);

if the g_timer1 is a global variable defined in the hook.dll, it probably isn't available in the timer function as the latter runs in the context of the hooked process. Hence, the timer proc would read a different value from the variable than being assigned when the SetTimer was called.

If that was true, you could/should replace the global variable by a function provided with the dll like

unsigned int& g_timerId()
{
    static unsigned int timerId = 0;
    return timerId;
}

which then could be used instead of the global variable:

   g_timerId() = SetTimer(NULL,1,200,gTimer1);

and

   KillTimer(NULL, g_timerId());


Note, the above wouldn't work if the SetTimer was called more than once. You could prevent a duplicate SetTimer call by

  if (g_timerId() == 0)
      g_timerId() = SetTimer(NULL,1,200,gTimer1);

and

   KillTimer(NULL, g_timerId());
   g_timerId() = 0;


0
 

Author Comment

by:VapiSoft
ID: 24304440
I found the problem.
The bug was that it entered the SetTimer twice before it entered the timer procedur.
Therefore the first g_timer1 was overwritten by the second timer.
When it Killed it killed only the second timer because it did not have the g_timer1 of the first time.
Thanks to you all.
0
 

Author Closing Comment

by:VapiSoft
ID: 31625828
As I wrote, I found the problem which was my mistake.
But I apperciate the help and good will from all the experts.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now