You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ZKEmkeeper SDK在Windows服务中OnAttTransactionEx事件不触发问题求助

问题排查与修复方案

核心问题1:SDK实例被垃圾回收

你的CZKEM objCZKEM是Connect_Net方法内的局部变量,方法执行完毕后该实例会被GC回收,直接导致后续设备事件无法被捕获。必须将CZKEM实例提升为类级别的成员变量,保证其生命周期与服务一致。

核心问题2:事件注册顺序错误

SDK要求先绑定事件回调,再调用RegEvent开启事件监听。你当前先调用RegEvent再绑定事件,顺序颠倒会导致事件触发逻辑失效。

次要问题:STA线程缺少消息循环

Windows服务中的STA线程需要消息循环才能处理COM组件的事件回调,你当前的while循环只是持续写日志,没有处理消息队列,会阻塞事件分发。


修复后的代码示例

1. 修改ZKemClient类,将CZKEM实例改为成员变量

public class ZKemClient
{
    // 提升为类成员,避免被GC回收
    private CZKEM _objCZKEM;
    private string _filepath;

    public ZKemClient(string filepath)
    {
        _filepath = filepath;
        _objCZKEM = new CZKEM();
    }

    public bool Connect_Net(string IPAdd, int Port)
    {
        bool bResult = false;
        try
        {
            if (_objCZKEM.Connect_Net(IPAdd, Port))
            {
                // 先注册事件,再调用RegEvent
                _objCZKEM.OnAttTransactionEx += zkemClient_OnAttTransactionEx;
                
                // RegEvent参数说明:1表示监听设备,32767是所有事件掩码
                if (_objCZKEM.RegEvent(1, 32767))
                {
                    WriteToFile("事件监听已开启");
                    bResult = true;
                }
                else
                {
                    WriteToFile("RegEvent调用失败");
                }
            }
            else
            {
                WriteToFile("设备连接失败");
            }
        }
        catch (Exception ex)
        {
            WriteToFile("Connect_Net() 异常->" + ex.Message);
        }
        return bResult;
    }

    private void zkemClient_OnAttTransactionEx(string EnrollNumber, int IsInValid, int AttState, int VerifyMethod, int Year, int Month, int Day, int Hour, int Minute, int Second, int WorkCode)
    {
        // 处理考勤事件逻辑
        WriteToFile($"收到考勤事件:卡号={EnrollNumber}, 时间={Year}-{Month}-{Day} {Hour}:{Minute}:{Second}");
    }

    private void WriteToFile(string content)
    {
        // 你的日志实现
        File.AppendAllText(_filepath, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {content}{Environment.NewLine}");
    }
}

2. 修改WorkedThread的消息循环

替换原来的死循环,使用Application.Run()启动STA线程的消息循环(需引用System.Windows.Forms):

private void WorkedThread()
{
    WriteToFile("Worker Thread Started.");                
                
    ZKemClient objZkeeper = new ZKemClient(filepath);
    this.isDeviceConnected = objZkeeper.Connect_Net("19x.x.x.24x", 4370);

    if (this.isDeviceConnected)
    {
        WriteToFile("Device connected.");
        // 启动STA线程的消息循环,处理COM事件
        Application.Run();
    }
    else
    {
        WriteToFile("Failed to connect to Device.");
    }
}

额外检查点

  • 确保服务运行账号有足够权限访问设备网络
  • 验证设备端是否开启事件推送功能(部分设备需在Web后台配置)
  • 检查SDK版本与设备固件版本是否兼容
  • 确认防火墙允许服务与设备的4370端口通信

内容的提问来源于stack exchange,提问作者Anup W

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 13:45:28