Also pass auf, Du hattest doch eben gesagt, dass bei dir dein
Application.Exit nicht gefeuert wird und Du anstelle dessen
WM_QUERYENDSESSION verwenden willst. Aber dann kann es sein, das der Timer geschlossen wird, auch wenn das beenden der Session von einem Programm verhindert wird.
Daher würde ich den Destruktor der Klasse verwenden, die den Timer verwaltet und darin die Dispose-Implementation aufrufen, die letztendlich den Timer schließt. Somit wird der Timer beendet, wenn alle Objekte des Programms beim Beenden zerstört werden.
//Edit: Ich hoffe ich hab dich jetzt nicht verwirrt. Meine Intension ging dahin, dass Du kein Form mehr brauchst, weil
WM_QUERYENDSESSION hier nicht viel bringt. Daher hätt ich im Destrukor deiner TimerKlasse einfach den Timer geschlossen. Wenn Du aber ein MainForm hast, verwendest die Dispose Methode deines MainForms um den Timer ordungsgemäß zu schließen.
Den Link zu dem Dispose Pattern Tutorial von TheCodeProject hast Dir hoffentlich intensiv angeschaut und aufgesaugt.
Hab Dir mal eine kleine Demo zu gemacht.