当前位置: 首页 > news >正文

【InterruptCallBack】- KRTS C++示例精讲(14)

InterruptCallBack示例讲解


文章目录

    • InterruptCallBack示例讲解
      • 结构说明
      • 代码说明


项目打开请查看【BaseFunction精讲】。

结构说明

在这里插入图片描述

InterruptCallBack.h :数据定义
InterruptCallBack.cpp :应用层源码
InterruptCallBack_dll.cpp :内核层源码

  • 其余文件说明请查看【BaseFunction精讲】中的结构说明。
    ps : 内核层中的数据、结构体需要一字节对齐,需要以MT方式构建

在这里插入图片描述

代码说明

InterruptCallBack.h :内核层和应用层共用此文件方便通过共享内存进行数据交换

/* Copyright (c) 2015-2025 by Kithara Software GmbH. All rights reserved. */  

//##############################################################################################################  
//  
//  文件:        InterruptCallBack.h  
//  
//  模块:       Interrupt Module, (RealTime Module)  
//  
//  描述:        用户空间应用程序和内核空间DLL之间的共享定义,用于编程中断例程  
//  
//  创建者:      p.gin 2015-09-08  
//  
//##############################################################################################################  

   /*=====================================================================*\  
   |                    *** 免责声明 ***                                    |  
   |                                                                       |  
   |       本代码仅是示例程序,您可以随意使用,我们不承担任何法律责任!         |  
   |                                                                       |  
   \*=====================================================================*/  

//##############################################################################################################  
//  
//  目的:  
//  
//  此示例演示如何在内核级别(ring 0)执行中断例程,即在操作系统内核上下文中运行。  
//  
//  该机制比应用层中断快得多,因为所有应用和大部分内核活动优先级较低。  
//  
//  但内核级执行对中断例程有限制:例如无法执行保存测量值到硬盘或可视化等应用层功能。  
//  
//  示例展示了为PCI设备或IRQ设备安装中断处理程序:  
//  选择中断源类型后,列出所有PCI设备供选择或指定IRQ,随后将中断程序安装到选定源。  
//  在激活三次后,事件通知应用退出并卸载内核。  
//  
//  注意:  
//  使用PCI中断需谨慎!大多数PCI组件不发送中断请求,若未正确确认PCI卡,系统将在首次中断后冻结!  
//  若无合适PCI设备,可通过按<enter>键模拟中断。  
//  
//  注意:  
//  请仅使用ISA硬件或内部芯片组组件的中断,避免使用PCI总线硬件的IRQ号!  
//  否则系统可能冻结,因PCI中断*必须*由内核级软件例程正确响应。  
//  若不确定IRQ号,请使用"0"并通过<enter>键模拟中断。  
//  
//##############################################################################################################  

#ifndef __SMP_INTERRUPTCALLBACK_H  
#define __SMP_INTERRUPTCALLBACK_H  

#include "../_KitharaSmp/_KitharaSmp.h"  

//--------------------------------------------------------------------------------------------------------------  
// SharedData 是用户定义的参数结构,用于内核DLL与用户应用通过共享内存交换信息  
// 可自由定义与系统位宽无关的参数  
//--------------------------------------------------------------------------------------------------------------  

struct SharedData {  
  KSHandle hKernel;                                     // 内核操作句柄  
  KSHandle hEvent;                                      // 中断事件句柄  
  KSHandle hInterrupt;                                  // 中断句柄  
  KSHandle hInterruptCallBack;                          // 中断回调句柄  

  int irq;                                              // IRQ号(0表示PCI中断)  
  int realtimeInterrupt;                                // 1=创建实时中断,否则用Windows中断  
  int counter;                                          // 中断处理程序递增的计数器  
  char pDeviceName[256];                                // PCI设备名称  
};  

#endif // __SMP_INTERRUPTCALLBACK_H  

InterruptCallBack.cpp :内核层和应用层共用此文件方便通过共享内存进行数据交换

/* Copyright (c) 2015-2025 by Kithara Software GmbH. All rights reserved. */

//##############################################################################################################
//
// 文件:        InterruptCallBack.cpp
//
// 模块: 		Interrupt Module, (RealTime Module)
//
// 描述:  		用户空间应用程序和内核空间DLL之间的共享定义,用于使用内核空间DLL的编程中断例程的示例
//
// 创建者:      p.gin 2015-09-08
//
//##############################################################################################################
  
   /*=====================================================================*\  
   |                    *** 免责声明 ***                                    |  
   |                                                                       |  
   |       本代码仅是示例程序,您可以随意使用,我们不承担任何法律责任!         |  
   |                                                                       |  
   \*=====================================================================*/  
   
//##############################################################################################################
//
// 目的:
//
// 这个示例代码演示了一个中断例程的编程,它将在内核级别(ring 0)执行,这意味着,在操作系统内核的上下文中。
//
// 这种机制将比应用程序级别的中断例程快得多,因为所有应用程序和大多数内核活动的优先级都较低。
//
// 另一方面,如果在内核级别执行,你的中断例程必须处理一些限制。
// 如:不允许将测量值保存到硬盘或可视化等应用程序功能。
//
// 这个例子展示了为PCI设备或IRQ设备安装中断处理程序。
// 在选择了中断源类型之后,所有PCI设备都显示出来,你可以选择一个,或者你被要求选择一个IRQ。
// 之后,中断程序将被安装到选定的源上。
// 在被激活三次之后,一个事件通知应用程序退出并卸载内核。
//
// 注意!
// 使用PCI中断时要小心!大多数PCI组件不发送中断请求。并且您自己的PCI卡需要正确确认,
// 否则系统将在第一次中断进入后冻结!所以,请使用这个例子作为模板。如果您没有合适的PCI设备,
// 请使用任何设备的中断模拟,
// 通过按<enter>键来模拟“中断”。
//
// 注意!
// 请只使用ISA硬件或内部芯片组组件的中断,特别是不要使用PCI总线上硬件的IRQ号!
// 否则,系统可能会冻结或崩溃,因为PCI中断*必须*由内核级别的软件例程正确响应。
// 如果你不知道合适的IRQ号,请使用“0”作为IRQ号,
// 通过按<enter>键来模拟“interrupts”。
//
//##############################################################################################################

//--------------------------------------------------------------------------------------------------------------
// 为了在主程序(用户层)和内核 DLL 之间共享数据结构的定义,我们使用了一个通用的头文件。
//--------------------------------------------------------------------------------------------------------------

#include "InterruptCallBack.h"

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// 别忘了输入你的序列号(6位客户编号),这是打开驱动程序所必需的。
//
// 如果你使用Demo版本,也可以使用"DEMO"代替。
// 如果你使用Beta版本,也可以使用"BETA"代替。
//
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

// 如上所述,定义的客户号 
const char _pCustomerNumber[] = "DEMO";

// 主程序入口
void runSample() {
  outputTxt("***** Kithara example program 'InterruptCallBack' *****");

  // 错误码定义,KSError 是 Kithara API 所有函数的返回类型,通过【KSError】可以查询接口的返回错误信息。
  KSError error;

  //------------------------------------------------------------------------------------------------------------
  // 打开驱动程序的第一步,所有KRTS程序必须进行的操作。
  // 只要该函数调用成功后,我们可以使用其他函数。如果打开失败,则无法调用其他函数。
  // 此函数接受您的客户编号作为参数,其中包含 Kithara(如果适用可以为"DEMO"或"BETA")。
  //------------------------------------------------------------------------------------------------------------

  error = KS_openDriver(
              _pCustomerNumber);                        // 客户序列号
  if (error != KS_OK) {
    outputErr(error, "KS_openDriver", "Unable to open the driver!");
    return;
  }

 //------------------------------------------------------------------------------------------------------------
  // 创建共享内存
  // 用于实时层中的DLL和此用户层应用程序之间的通信。
  //------------------------------------------------------------------------------------------------------------

  KSHandle hSharedMemory;
  error = KS_createSharedMemEx(
              &hSharedMemory,                           // 新共享内存句柄的写入地址
              "",                                       // 共享内存名称
              sizeof(SharedData),                       // 共享内存大小
              KSF_NO_FLAGS);                            // 标志位,此处无
  if (error != KS_OK) {
    outputErr(error, "KS_createSharedMemEx", "Unable to create shared memory!");
    KS_closeDriver();
    return;
  }

  //------------------------------------------------------------------------------------------------------------
  // 要访问共享内存,应用程序需要获取指向已分配共享内存的指针
  // 使用刚创建的共享内存句柄。
  //------------------------------------------------------------------------------------------------------------

  SharedData* pApp;
  error = KS_getSharedMemEx(
              hSharedMemory,                            // 共享内存的句柄
              (void**)&pApp,                            // SharedData结构指针的地址
              KSF_NO_FLAGS);                            // 标志位,此处无
  if (error != KS_OK) {
    outputErr(error, "KS_getSharedMemEx", "Unable to map shared memory!");
    KS_closeDriver();
    return;
  }

  //------------------------------------------------------------------------------------------------------------
  // 确定系统的位数,以决定加载32位还是64位内核DLL。
  //------------------------------------------------------------------------------------------------------------

  KSSystemInformation systemInfo;                       // KSSystemInformation实例
  systemInfo.structSize = sizeof(KSSystemInformation);  // 不要忘记初始化structSize!
  error = KS_getSystemInformation(
              &systemInfo,                              // KSSystemInformation结构地址
              KSF_NO_FLAGS);                            // 标志位(未使用)
  if (error != KS_OK) {
    outputErr(error, "KS_getSystemInformation", "无法获取系统信息以区分位数!");
    KS_closeDriver();
    return;
  }

  //------------------------------------------------------------------------------------------------------------
  // 要使用内核层DLL中的函数,必须先加载该DLL。
  //
  // 注意!DLL必须能被加载器找到,因此应将其放置在搜索路径包含的目录中!
  //
  // 因为我们想通过共享内存传递已加载内核的句柄,所以在加载内核时不使用初始化函数,
  // 而是在填充共享内存结构中的内核句柄和初始化所需信息后显式调用初始化函数。
  //------------------------------------------------------------------------------------------------------------

  error = KS_loadKernel(
              &pApp->hKernel,                           // 内核句柄的写入地址
              systemInfo.isSys64Bit ?                   // DLL名称
                "InterruptCallBack_64.dll" :            // 64位或
                "InterruptCallBack_32.dll",             // 32位内核
              NULL,                                     // 初始化函数名称(未使用)
              NULL,                                     // 初始化参数(未使用)
              KSF_KERNEL_EXEC);                         // 标志位,此处加载到内核地址空间
  if (error != KS_OK) {
    outputErr(error, "KS_loadKernel", "Unable to load DLL! Is the DLL in the search path?");
    KS_closeDriver();
    return;
  }

  pApp->realtimeInterrupt = 0;
#ifdef KS_REALTIME_MODULE_INCLUDED
  outputTxt("Please choose if the interrupt should be executed in:");
  outputTxt("1: Realtime context");
  outputTxt("2: Windows context");
  if (inputDec("", 1) == 1)
    pApp->realtimeInterrupt = 1;
#endif // KS_REALTIME_MODULE_INCLUDED

  //------------------------------------------------------------------------------------------------------------
  // 让用户选择中断的触发源类型。
  //------------------------------------------------------------------------------------------------------------

  bool simulate = false;                                // 用户选择是否模拟中断的标志

  outputTxt("Please choose if the interrupt should be triggered by:");
  outputTxt("1: PCI device");
  outputTxt("2: IRQ");
  outputTxt("0: abort");
  int interruptSourceType = inputDec("", 0);
  if (interruptSourceType != 1 && interruptSourceType != 2) {
    outputTxt("Closing example program 'InterruptCallBack'!");
    KS_closeDriver();
    return;
  }

  if (interruptSourceType == 1) {                       // 使用PCI设备作为中断源

    //----------------------------------------------------------------------------------------------------------
    // 现在查询并显示所有PCI设备的名称。
    //----------------------------------------------------------------------------------------------------------

    char pDeviceName[256];
    outputTxt(" ");
    outputTxt("Following PCI devices were found:");

    for (int i = 0; i < 100; ++i) {
      error = KS_enumDevices(
                  "PCI",                                // 'PCI'搜索PCI设备
                  i,                                    // 枚举索引,从0开始
                  pDeviceName,                          // PCI设备名称缓冲区
                  KSF_NO_FLAGS);                        // 标志位,此处无
      if (error != KS_OK) {
        if (KSERROR_CODE(error) != KSERROR_DEVICE_NOT_FOUND) {
          outputErr(error, "KS_enumDevices", "Unable to query PCI device name!");
          outputTxt(" ");
          KS_closeDriver();
          return;
        }
        if (KSERROR_CODE(error) == KSERROR_DEVICE_NOT_FOUND && !i) {
          outputTxt("No PCI devices found!");
          outputTxt(" ");
          KS_closeDriver();
          return;
        }
        break;
      }
      outputDec(i, "  ", ": ", false);
      outputTxt(pDeviceName);
    }

    //----------------------------------------------------------------------------------------------------------
    // 请输入要使用的设备索引。
    //----------------------------------------------------------------------------------------------------------

    do {
      int deviceIndex = inputDec("Device number (-1 = Exit): ", 0);
      if (deviceIndex == -1) {
        outputTxt("Closing example program 'InterruptCallBack'!");
        KS_closeDriver();
        return;
      }

      //--------------------------------------------------------------------------------------------------------
      // 获取所选设备名称。
      //--------------------------------------------------------------------------------------------------------

      error = KS_enumDevices(
                  "PCI",                                // 'PCI'搜索PCI设备
                  deviceIndex,                          // 所选设备的索引
                  pApp->pDeviceName,                    // PCI设备名称缓冲区
                  KSF_NO_FLAGS);                        // 标志位,此处无
      if (KSERROR_CODE(error) == KSERROR_DEVICE_NOT_FOUND)
        outputTxt("Sorry, this device can not be found!");
      else if (error != KS_OK) {
        outputErr(error, "KS_enumDevices", "Unable to query selected PCI device name!");
        KS_closeDriver();
        return;
      }
    } while (error != KS_OK);

    outputTxt(" ");
    outputTxt("Selected device: ", false);
    outputTxt(pApp->pDeviceName);
    pApp->irq = 0;                                      // 表示无IRQ中断源


    //----------------------------------------------------------------------------------------------------------
    // 是否希望通过按<enter>键模拟设备中断?
    //----------------------------------------------------------------------------------------------------------

    outputTxt(" ");
    simulate = inputDec("Simulate the interrupt for this device? (0 = No, <enter> = Yes) ", 1) != 0;
  }
  else {                                                // 使用IRQ作为中断源
    //----------------------------------------------------------------------------------------------------------
    // 要在哪个IRQ上安装中断处理程序?
    //
    // 注意!请不要使用PCI总线上的硬件IRQ编号!否则系统可能挂起或崩溃,
    // 因为PCI中断*必须*由内核层的软件例程正确响应。
    // 如果您不知道有效的IRQ编号,请使用0作为IRQ编号。这将允许您通过按<enter>键模拟"中断"。
    // PIC系统支持的最大IRQ编号为15,APIC系统为23。
    //----------------------------------------------------------------------------------------------------------

    outputTxt(" ");
    outputTxt("Please enter the hardware IRQ number or 0 for simulation using keyboard.");
    pApp->irq = inputDec("IRQ number of the hardware (1 .. 15/23): ", 0);
    outputTxt(" ");
    if (pApp->irq > 23 || pApp->irq < 0) {
      outputTxt(" ");
      outputTxt("Sorry, this IRQ number is not supported! Using simulation instead...");
      pApp->irq = 0;
    }

    outputTxt(" ");
    if (pApp->irq > 0) {
      outputDec(pApp->irq, "Running on the IRQ ", ".");
    }
    else {
      outputTxt("You can simulate an IRQ by pressing the <enter> key.");


      //--------------------------------------------------------------------------------------------------------
      // 尝试使用空闲的未使用IRQ。我们尝试使用软盘驱动器的IRQ。如果无效,
      // 请在您的系统上搜索其他空闲IRQ。
      //--------------------------------------------------------------------------------------------------------

      pApp->irq = 6;                                    // IRQ 6 = 软盘驱动器(可能)
      simulate = true;
    }
  }
  
  //------------------------------------------------------------------------------------------------------------
  // 现在调用内核的初始化函数,并传递共享内存的句柄,
  // 以便内核可以从句柄获取共享内存指针,并根据共享内存中的信息分配必要的资源。
  //------------------------------------------------------------------------------------------------------------

  error = KS_execKernelFunctionEx(
              pApp->hKernel,                            // 内核句柄
              "_initFunction",                          // 函数名称
              hSharedMemory,                            // 共享内存句柄
              KS_INVALID_HANDLE,                        // 上下文(未使用)
              KSF_NO_FLAGS);                            // 标志位(未使用)
  if (error != KS_OK) {
    outputErr(error, "KS_execKernelFunctionEx", "Unable to initialize the kernel DLL!");
    KS_closeDriver();
    return;
  }

  waitTime(100 * ms);


  //------------------------------------------------------------------------------------------------------------
  // 如果请求模拟:等待3次键盘输入以通过共享内存中的中断句柄触发中断,
  // 否则等待5秒接收传入的中断。
  //------------------------------------------------------------------------------------------------------------

  if (simulate) {
    for (int i = 1; i < 4; ++i) {
      waitTime(10 * ms);
      outputDec(i, "Please press enter (", ")", false);
      inputTxt(" ", "<enter>");
      error = KS_simulateInterrupt(
                  pApp->hInterrupt);                    // 中断句柄
      if (error != KS_OK)
        outputErr(error, "KS_simulateInterrupt", "Unable to simulate the interrupt!");
    }
  }
  else {


    //----------------------------------------------------------------------------------------------------------
    // 现在等待事件信号。该事件由内核层的回调函数触发。
    // 为确保在事件未触发时不会挂起,我们设置了合理的超时值。
    //
    // 注意!超时值不应用于精确延时,因为它基于操作系统机制!
    //----------------------------------------------------------------------------------------------------------

    outputTxt("You have 5 seconds to generate 3 interrupts.");

    error = KS_waitForEvent(
                pApp->hEvent,                           // 事件句柄
                KSF_NO_FLAGS,                           // 标志位(未使用)
                5 * s);                                 // 超时值,以100纳秒为单位 = 5秒
    if (error != KS_OK)
      outputErr(error, "KS_waitForEvent", "Waiting for event failed!");
  }

  outputDec(pApp->counter, "The interrupt has been called ", " times.");


  //------------------------------------------------------------------------------------------------------------
  // 现在让DLL清理其分配的资源。
  //------------------------------------------------------------------------------------------------------------

  error = KS_execKernelFunctionEx(
              pApp->hKernel,                            // 内核句柄
              "_exitFunction",                          // 函数名称
              KS_INVALID_HANDLE,                        // 函数调用参数(未使用)
              KS_INVALID_HANDLE,                        // 上下文(未使用)
              KSF_NO_FLAGS);                            // 标志位(未使用)
  if (error != KS_OK) {
    outputErr(error, "KS_execKernelFunctionEx", "Error while deallocating resources on kernel level!");
    KS_closeDriver();
    return;
  }


  //------------------------------------------------------------------------------------------------------------
  // 使用共享句柄卸载内核DLL。
  // 尽管KS_closeDriver()会释放所有分配的资源(如共享内存和加载的内核),
  // 但显式释放已分配的资源是良好的编程习惯。
  //------------------------------------------------------------------------------------------------------------

  error = KS_freeKernel(
              pApp->hKernel);                           // 内核句柄
  if (error != KS_OK)
    outputErr(error, "KS_freeKernel", "Unable to unload the kernel!");


  //------------------------------------------------------------------------------------------------------------
  // 使用本地存储的句柄释放共享内存。
  //------------------------------------------------------------------------------------------------------------

  error = KS_freeSharedMemEx(
              hSharedMemory,                            // 共享内存句柄
              KSF_NO_FLAGS);                            // 标志位(未使用)
  if (error != KS_OK)
    outputErr(error, "KS_freeSharedMemEx", "Unable to remove shared memory!");


  //------------------------------------------------------------------------------------------------------------
  // 最后我们必须关闭驱动程序以释放所有分配的资源。
  //------------------------------------------------------------------------------------------------------------

  error = KS_closeDriver();
  if (error != KS_OK)
    outputErr(error, "KS_closeDriver", "Unable to close the driver!");

  waitTime(500 * ms);
  outputTxt(" ");
  outputTxt("End of program 'InterruptCallBack'.");
}


InterruptCallBack_dll.cpp :内核层和应用层共用此文件方便通过共享内存进行数据交换

/* Copyright (c) 2015-2025 by Kithara Software GmbH. All rights reserved. */

//##############################################################################################################
//
// 文件:         InterruptCallBack_dll.cpp
//
// 模块: 		Interrupt Module, (RealTime Module)
//
// 描述:  		用户空间应用程序和内核空间DLL之间的共享定义,用于使用内核空间DLL的编程中断例程的示例
//
// 创建者:       p.gin 2015-09-08
//
//##############################################################################################################
  
   /*=====================================================================*\  
   |                    *** 免责声明 ***                                    |  
   |                                                                       |  
   |       本代码仅是示例程序,您可以随意使用,我们不承担任何法律责任!         |  
   |                                                                       |  
   \*=====================================================================*/  

//##############################################################################################################
//
// 目的:
//
// 这个示例代码演示了一个中断例程的编程,它将在内核级别(ring 0)执行,这意味着,在操作系统内核的上下文中。
//
// 这种机制将比应用程序级别的中断例程快得多,因为所有应用程序和大多数内核活动的优先级都较低。
//
// 另一方面,如果在内核级别执行,你的中断例程必须处理一些限制。
// 如:不允许将测量值保存到硬盘或可视化等应用程序功能。
//
// 这个例子展示了为PCI设备或IRQ设备安装中断处理程序。
// 在选择了中断源类型之后,所有PCI设备都显示出来,你可以选择一个,或者你被要求选择一个IRQ。
// 之后,中断程序将被安装到选定的源上。
// 在被激活三次之后,一个事件通知应用程序退出并卸载内核。
//
// 注意!
// 使用PCI中断时要小心!大多数PCI组件不发送中断请求。并且您自己的PCI卡需要正确确认,
// 否则系统将在第一次中断进入后冻结!所以,请使用这个例子作为模板。如果您没有合适的PCI设备,
// 请使用任何设备的中断模拟,
// 通过按<enter>键来模拟“中断”。
//
// 注意!
// 请只使用ISA硬件或内部芯片组组件的中断,特别是不要使用PCI总线上硬件的IRQ号!
// 否则,系统可能会冻结或崩溃,因为PCI中断*必须*由内核级别的软件例程正确响应。
// 如果你不知道合适的IRQ号,请使用“0”作为IRQ号,
// 通过按<enter>键来模拟“interrupts”。
//
//##############################################################################################################


//--------------------------------------------------------------------------------------------------------------
// 为了在主程序与内核DLL之间共享数据结构定义,我们使用公共头文件。
//--------------------------------------------------------------------------------------------------------------

#include "InterruptCallBack.h"


//--------------------------------------------------------------------------------------------------------------
// 共享内存用于内核空间DLL与用户空间应用程序之间的数据共享。
//--------------------------------------------------------------------------------------------------------------

SharedData* _pSys = NULL;


//--------------------------------------------------------------------------------------------------------------
// 声明将在文件末尾定义的回调函数。
//--------------------------------------------------------------------------------------------------------------

KSError __stdcall interruptCallBack(void* /*pArgs*/, void* /*pContext*/);


//--------------------------------------------------------------------------------------------------------------
// 初始化函数(内核层)
// 在加载内核后被调用,接收共享内存句柄作为参数
//
// 注意!所有函数应声明为'extern "C"'!
// 否则加载器无法解析函数名。
// 需要通过'__declspec(dllexport)'显式导出函数。
//--------------------------------------------------------------------------------------------------------------

extern "C" KSError __declspec(dllexport) __stdcall _initFunction(void* pArgs, void* /*pContext*/) {
  KSError error;


  //------------------------------------------------------------------------------------------------------------
  // 共享内存指针通过KS_execKernelFunctionEx()的pArgs参数传递
  //------------------------------------------------------------------------------------------------------------

  _pSys = (SharedData*)pArgs;
  _pSys->counter = 0;                                   // 清零中断计数器


  //------------------------------------------------------------------------------------------------------------
  // 创建事件对象
  // 后续用户层将等待此事件以在卸载内核前调用_exitFunction
  //------------------------------------------------------------------------------------------------------------

  error = KS_createEvent(
              &_pSys->hEvent,                           // 新事件句柄的写入地址
              "MyInterruptCallBackEvent",               // 事件名称
              KSF_NO_FLAGS);                            // 标志位,此处无
  if (error != KS_OK)
    return error;


  //------------------------------------------------------------------------------------------------------------
  // 创建中断请求发生时调用的回调函数
  //------------------------------------------------------------------------------------------------------------

  int flags = _pSys->realtimeInterrupt == 1 ? KSF_DIRECT_EXEC : KSF_KERNEL_EXEC;
  error = KS_createCallBack(
              &_pSys->hInterruptCallBack,               // 新回调句柄的写入地址
              interruptCallBack,                        // 回调函数指针
              NULL,                                     // 回调参数(未使用)
              flags,                                    // 根据用户选择的执行上下文标志
              0);                                       // 优先级(仅用户层使用)
  if (error != KS_OK)
    return error;


  //------------------------------------------------------------------------------------------------------------
  // 创建中断处理程序并在选定的IRQ或PCI设备上安装回调
  //------------------------------------------------------------------------------------------------------------

  flags = _pSys->realtimeInterrupt == 1 ? KSF_REALTIME_EXEC : 0;
  if (_pSys->irq > 0)
    error = KS_createInterrupt(
                &_pSys->hInterrupt,                     // 新中断句柄的写入地址
                _pSys->irq,                             // IRQ线路编号
                _pSys->hInterruptCallBack,              // 回调句柄
                flags);                                 // 实时上下文标志
  else
    error = KS_createDeviceInterruptEx(
                &_pSys->hInterrupt,                     // 新中断句柄的写入地址
                _pSys->pDeviceName,                     // PCI设备名称
                _pSys->hInterruptCallBack,              // 回调句柄
                flags);                                 // 实时上下文标志
  if (error != KS_OK)
    return error;

  return KS_OK;
}


//--------------------------------------------------------------------------------------------------------------
// 清理函数:移除已安装的中断处理程序、回调函数和事件对象
//--------------------------------------------------------------------------------------------------------------

extern "C" KSError __declspec(dllexport) __stdcall _exitFunction(void* /*pArgs*/, void* /*pContext*/) {
  if (_pSys == NULL)                                    // 共享内存未映射!
    return KSERROR_FUNCTION_NOT_AVAILABLE;              // _initFunction未被调用?

  KSError error;


  //------------------------------------------------------------------------------------------------------------
  // 通过中断句柄移除中断对象
  // 注意:中断可能仍在运行,移除前无需显式停止
  //------------------------------------------------------------------------------------------------------------

  error = KS_removeInterrupt(
              _pSys->hInterrupt);                       // 中断句柄
  if (error != KS_OK)
    return error;


  //------------------------------------------------------------------------------------------------------------
  // 通过回调句柄移除回调对象
  //------------------------------------------------------------------------------------------------------------

  error = KS_removeCallBack(
              _pSys->hInterruptCallBack);               // 回调句柄
  if (error != KS_OK)
    return error;


  //------------------------------------------------------------------------------------------------------------
  // 通过事件句柄移除事件对象
  //------------------------------------------------------------------------------------------------------------

  error = KS_closeEvent(
              _pSys->hEvent);                           // 事件句柄
  if (error != KS_OK)
    return error;

  return KS_OK;
}


//--------------------------------------------------------------------------------------------------------------
// 中断回调函数:每次中断触发时被调用
//--------------------------------------------------------------------------------------------------------------

KSError __stdcall interruptCallBack(void* /*pArgs*/, void* /*pContext*/) {


  //------------------------------------------------------------------------------------------------------------
  // 禁止屏幕输出,仅递增共享内存中的计数器
  //------------------------------------------------------------------------------------------------------------

  ++_pSys->counter;                                     // 递增共享内存中的计数器


  //------------------------------------------------------------------------------------------------------------
  // 本示例预期收到3次中断后触发事件,并通过返回错误码终止回调
  //------------------------------------------------------------------------------------------------------------

  if (_pSys->counter == 3) {
    KS_setEvent(                                        // 通知用户层等待的事件
      _pSys->hEvent);                                   // 事件句柄
    return KSERROR_CATEGORY_USER;                       // 返回非零值终止回调
  }


  //------------------------------------------------------------------------------------------------------------
  // 返回值非零时将取消中断注册
  // 多数情况下应返回0(KS_OK)保持中断激活
  //------------------------------------------------------------------------------------------------------------

  return KS_OK;
}


//--------------------------------------------------------------------------------------------------------------
// 必须实现的DllMain函数(实际不会被执行)
//
// 初始化操作应通过自定义初始化函数完成,如本示例所示:
// 1. 通过KS_loadKernel()加载内核时不指定初始化函数
// 2. 加载后显式调用_initFunction并传递所需参数
//--------------------------------------------------------------------------------------------------------------

#define WIN32_LEAN_AND_MEAN
#pragma pack(push, 8)
#include <windows.h>
#pragma pack(pop)

BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID pReserved) {
  return TRUE;
}

相关文章:

  • java自带日志系统介绍(JUL)以及和Log4j 2、Logback、SLF4J不同日志工具的对比
  • 【解决方案】RAGFlow部分问题清单及解决方案备忘1
  • 专业视角:set 和 multiset的原理与应用解析
  • 星海智算:风月ComfyUI_SD3.5使用教程
  • 嵌入式开发工程师笔试面试指南-模电基础
  • uni-app vue2 记住密码功能
  • Python实现的用于处理协作车辆进入路口遮挡自车路径的情况
  • [Space Shooter_1] Environment | CMake | SDL
  • 防爆手机如何突破“安全与效率“悖论?解析AORO M8的双驱动创新
  • 工程化与框架系列(31)--前端依赖管理实践
  • Redis 2025/3/9
  • 【开源免费】基于SpringBoot+Vue.JS光影视频平台(JAVA毕业设计)
  • Hutool RedisDS:Java开发中的Redis极简集成与高阶应用
  • 边缘计算(Edge Computing)
  • 化合物上下游数据助力压缩研发周期
  • springboot 云原生介绍
  • 电商平台数据高效集成:旺店通旗舰版到MySQL方案解析
  • C++程序设计语言笔记——抽象机制:派生类
  • git报错:“fatal:refusing to merge unrelated histories“
  • 机试准备第16天
  • 北京百度seo排名/西安seo外包优化
  • 成都大型网站建设公司/爱站网备案查询
  • 一站式服务就像一个什么/百度经验app下载
  • 律师怎样做网站/游戏代理平台
  • 黄冈网站建设设计/b站推广软件
  • php网站管理系统下载/app营销策略有哪些