在 Windows 服务中从事件处理程序启动计时器
Posted
技术标签:
【中文标题】在 Windows 服务中从事件处理程序启动计时器【英文标题】:Start Timer from an Event Handler, in Windows Service 【发布时间】:2021-07-23 18:50:27 【问题描述】:我有一个内置于 vb.net 的 Windows 服务,用于接收来自 MQTT 服务器的消息。通过附加到事件处理程序的 Sub 接收和处理消息。工作正常。
另外,我需要启动一个定时器,它会同时向“蜂鸣器”发送一个信号,蜂鸣器会发出哔哔声、停止、哔哔声……这个子例程本身就可以正常工作。
在 Windows 服务和 Windows 窗体中,它都不能完美运行。 Timer 必须由链接到 Event Handler 的 Sub 启用(一旦收到并处理 MQTT 消息,启动计时器)。定时器通常设置为 1000ms。子程序在 Timer 到达 1000ms 之前完成,并且永远不会触发 Tick 事件。
在 Windows 窗体中,我使用了 Me.Invoke。 Timer's Tick 事件按预期触发。但是 Windows 服务中不存在“me.invoke”。我不知道如何继续触发 Tick 事件。
在 Windows 窗体中,我能够创建一个委托并使用 Me.Invoke 调用 RefreshMqttScreen...
所以问题是:一旦 MqttMessageReceived 子程序完成运行,如何让计时器继续运行?
如果 VB 不能满足我的需求,我可以使用 C#...
谢谢
AddHandler _mqttClient.ApplicationMessageReceived, AddressOf MqttMessageReceived
Public Sub MqttMessageReceived(ByVal sender As Object, ByVal e As MqttApplicationMessageReceivedEventArgs)
RefreshMQTTScreen(some parameters here)
End Sub
Private Sub RefreshMQTTScreen(....)
indexBuzzer = 1
TimerBuzzer.Interval = buzzer.intDuree
TimerBuzzer.Enabled = True
End Sub
Private Sub TimerBuzzer_Tick(sender As Object, e As EventArgs) Handles TimerBuzzer.Tick
TimerBuzzer.Enabled = False
indexBuzzer += 1
If collBuzzerActif.Count >= indexBuzzer Then
Dim buzzer As Derby.ClsBuzzer
buzzer = collBuzzerActif(indexBuzzer)
If buzzer.boolOn And buzzer.intDuree > 0 Then
ChangerStatutDataLogger(True)
If collBuzzerActif.Count >= indexBuzzer + 1 Then
TimerBuzzer.Interval = buzzer.intDuree
TimerBuzzer.Enabled = True
End If
Else
ChangerStatutDataLogger(False)
If collBuzzerActif.Count >= indexBuzzer + 1 Then
TimerBuzzer.Interval = buzzer.intDuree
TimerBuzzer.Enabled = True
End If
End If
End If
End Sub
【问题讨论】:
服务默认使用系统管理员运行,没有环境变量,也没有凭据。最好的办法是使用用户帐户启动服务。打开 Windows 服务控制台(开始菜单 > 控制面板 > 管理工具 > 服务)。 ...单击登录选项卡。 ...单击此帐户单选按钮。 ...单击“浏览”按钮后,将出现“选择用户或服务帐户”对话框。 【参考方案1】:您可以使用任务和一些手动重置事件来代替计时器。当您的服务启动时执行此 ONCE,
_TimerBuzzerTask = Task.Run(Sub() TimerBuzzer_Tick())
然后进行这些更改
Private Sub RefreshMQTTScreen(....)
indexBuzzer = 1
TimerBuzzerInterval = buzzer.intDuree
_TimerBuzzer_Enabled.Set()
End Sub
Private _TimerBuzzerTask As Task
Private _TimerBuzzer_Enabled As New Threading.ManualResetEvent(False)
Private _TimerBuzzer As New Threading.ManualResetEvent(False) '_TimerBuzzer.Set to end task
Private TimerBuzzerInterval As Integer = 1000
Private Sub TimerBuzzer_Tick()
Do
_TimerBuzzer_Enabled.WaitOne() 'to enable _TimerBuzzer_Enabled.Set()
_TimerBuzzer_Enabled.Reset()
If collBuzzerActif.Count >= indexBuzzer Then
Dim buzzer As Derby.ClsBuzzer
buzzer = collBuzzerActif(indexBuzzer)
If buzzer.boolOn AndAlso buzzer.intDuree > 0 Then
ChangerStatutDataLogger(True)
If collBuzzerActif.Count >= indexBuzzer + 1 Then
TimerBuzzerInterval = buzzer.intDuree
_TimerBuzzer_Enabled.Set()
End If
Else
ChangerStatutDataLogger(False)
If collBuzzerActif.Count >= indexBuzzer + 1 Then
TimerBuzzerInterval = buzzer.intDuree
_TimerBuzzer_Enabled.Set()
End If
End If
End If
Loop While _TimerBuzzer.WaitOne(TimerBuzzerInterval) 'ticks every second
End Sub
如果您的服务停止执行此操作,
_TimerBuzzer.Set
由于显而易见的原因,我无法对此进行测试。
【讨论】:
以上是关于在 Windows 服务中从事件处理程序启动计时器的主要内容,如果未能解决你的问题,请参考以下文章
在Twisted,Oscar中从外部事件处理程序发送ICQ消息