我确实写了一个windows服务,可以使用dll连接到网络设备。所以一切都很好,但事件处理程序在win服务中不起作用!这是我的代码:
我的自定义类代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyNewService
{
public class zkemkeeperHandler
{
public event EventHandler OnFinger;
public event EventHandler<VerifyEventArgs> OnVerify;
private System.Diagnostics.EventLog eventLog1 = new System.Diagnostics.EventLog();
public zkemkeeper.CZKEMClass axCZKEM1 = new zkemkeeper.CZKEMClass();
private bool bIsConnected = false;
private int iMachineNumber = 1;
public zkemkeeperHandler()
{
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).BeginInit();
this.eventLog1.Log = "DoDyLog";
this.eventLog1.Source = "DoDyLogSource";
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).EndInit();
eventLog1.WriteEntry("zkemkeeperHandler constructor");
}
public void startService()
{
eventLog1.WriteEntry("start service for (192.168.0.77:4370)");
bIsConnected = axCZKEM1.Connect_Net("192.168.0.77", Convert.ToInt32("4370"));
if (bIsConnected == true)
{
eventLog1.WriteEntry("bIsConnected == true !");
iMachineNumber = 1;
if (axCZKEM1.RegEvent(iMachineNumber, 65535))
{
this.axCZKEM1.OnFinger += new kemkeeper._IZKEMEvents_OnFingerEventHandler(axCZKEM1_OnFinger);
this.axCZKEM1.OnVerify += new zkemkeeper._IZKEMEvents_OnVerifyEventHandler(axCZKEM1_OnVerify);
//This Log Appears in Event Viewer
eventLog1.WriteEntry("Define events (OnFingers and OnVerify) !");
//This Line Fires Event in Service1.cs for testing event handler
Finger(EventArgs.Empty);
}
}
else
{
eventLog1.WriteEntry("Unable to connect the device");
}
}
public void stopService()
{
if (bIsConnected) {axCZKEM1.Disconnect(); bIsConnected = false;}
}
//This method doesn't run :(
private void axCZKEM1_OnFinger()
{
Finger(EventArgs.Empty);
}
//This method doesn't run too :(
private void axCZKEM1_OnVerify(int iUserID)
{
VerifyEventArgs args = new VerifyEventArgs();
args.UserID = iUserID;
Verify(args);
}
public class VerifyEventArgs : EventArgs
{
public int UserID { get; set; }
}
protected virtual void Finger(EventArgs e)
{
EventHandler handler = OnFinger;
if (handler != null)
handler(this, e);
}
protected virtual void Verify(VerifyEventArgs e)
{
EventHandler<VerifyEventArgs> handler = OnVerify;
if (handler != null)
handler(this, e);
}
}
}
我的主要服务类别代码:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Linq;
using System.Threading;
namespace MyNewService
{
public class Service1 : System.ServiceProcess.ServiceBase
{
private System.Diagnostics.EventLog eventLog1;
private System.ComponentModel.Container components = null;
zkemkeeperHandler zkh;
public Service1()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("DoDyLogSource"))
{
System.Diagnostics.EventLog.CreateEventSource("DoDyLogSource", "DoDyLog");
}
eventLog1.Source = "DoDyLogSource";
eventLog1.Log = "DoDyLog";
eventLog1.WriteEntry("Preparing to start service");
try
{
startZKHandler();
}
catch (Exception ex)
{
eventLog1.WriteEntry(ex.InnerException.Message);
}
}
private void startZKHandler()
{
eventLog1.WriteEntry("creating zkemkeeper handler class");
zkh = new zkemkeeperHandler();
zkh.OnFinger += OnFinger;
zkh.OnVerify += OnVerify;
zkh.startService();
}
private void stopZKHandler()
{
eventLog1.WriteEntry("Disconnecting from device (192.168.0.77)...");
zkh.stopService();
}
private void writeLog2DB(string message)
{
try
{
eventLog1.WriteEntry("writing to database");
DB.DBase.LogTable.AddObject(new LogTable
{
ID = ++DB.IDCounter,
deviceLog = message
});
DB.DBase.SaveChanges();
}
catch (Exception ex)
{
eventLog1.WriteEntry(ex.Message + " - " + ex.InnerException.Message);
}
this.EventLog.Log = "Event Stored in DB.";
}
// The main entry point for the process
static void Main()
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new MyNewService.Service1()};
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
private void InitializeComponent()
{
this.eventLog1 = new System.Diagnostics.EventLog();
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).BeginInit();
this.eventLog1.Log = "DoDyLog";
this.eventLog1.Source = "DoDyLogSource";
this.ServiceName = "MyNewService";
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).EndInit();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
protected override void OnStart(string[] args)
{
// TODO: Add code here to start your service.
eventLog1.WriteEntry("my service started");
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
eventLog1.WriteEntry("my service stoped");
stopZKHandler();
}
protected override void OnContinue()
{
eventLog1.WriteEntry("my service is continuing in working");
}
private void OnFinger(object sender, EventArgs e)
{
eventLog1.WriteEntry("Finger Event Raised");
}
private void OnVerify(object sender, zkemkeeperHandler.VerifyEventArgs e)
{
eventLog1.WriteEntry("Verify Event Raised");
}
}
}
我犯了什么错?请帮帮我!
我编写的Windows服务可以引发自定义事件,但不能引发我的dll事件!
我知道这个线程很旧了,但我昨天遇到了这个问题,在浪费了很多小时之后,现在我终于找到了解决方案。问题是,COM对象必须从STA线程创建,然后,为了正确调度事件,同一STA线程(完全相同)必须泵送COM消息。这可以通过调用循环中的Application.DoEvents()或Application.Run().来完成
所以这是我的工作代码(它可以工作,即使是作为Vista+中的非交互式Windows服务,我使用的是Windows 8.1)
Thread createComAndMessagePumpThread = new Thread(() =>
{
this.Device = new CZKEMClass(); //Here create COM object
Application.Run();
});
createComAndMessagePumpThread.SetApartmentState(ApartmentState.STA);
createComAndMessagePumpThread.Start();
创建设备后,您可以从任何线程注册事件,这些事件由创建COM对象的STA线程调度。
在Windows窗体应用程序中,这在不执行此操作的情况下有效,因为STA主线程运行调用application.run(form).application.run()的窗体,然后调度COM事件和Windows GUI事件等事件,因此不需要使用上述技巧。
重新提出这个问题,因为我刚刚处理了一个相关的问题。显然,OP正在使用一些COM STA对象,这些对象需要一个STA线程和一个功能消息泵循环才能正常运行。默认情况下,Windows服务执行模型没有此功能。有关更多详细信息,请访问链接的答案。
您不能在Windows服务中使用事件。存在几个原因,为什么不呢?但我想为zkemgeeper提供一个的解决方案:
ZK发布了一个zkemkeeper.dll作为COM对象,用于处理Windows应用程序。当您将应用程序作为windows服务运行时,所有设备事件都将被激发,并且不会在应用程序中引发。尝试将引用System.Windows.Forms添加到项目中,并在成功连接后添加行:
Application.Run();