DriverEntry.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // DriverEntry.cpp - KMDF 驱动入口
  2. // 职责:初始化 WDF 驱动对象、注册 EvtDeviceAdd(PnP 过滤驱动)
  3. // 创建控制设备 \\.\CommModifyKit 接收 DLL 的 IOCTL
  4. // 注意:本驱动作为串口设备类的 UpperFilters 加载
  5. // 当 PnP Manager 创建串口 PDO 时,调用 EvtDeviceAdd attach 过滤设备
  6. #include <ntddk.h>
  7. #include <wdf.h>
  8. #include "DeviceContext.h"
  9. #include "QueueCallback.h"
  10. #include "ClientConnection.h"
  11. #include "SerialFilter.h"
  12. extern "C" {
  13. DRIVER_INITIALIZE DriverEntry;
  14. EVT_WDF_DRIVER_DEVICE_ADD EvtDeviceAdd;
  15. EVT_WDF_DRIVER_UNLOAD EvtDriverUnload;
  16. EVT_WDF_OBJECT_CONTEXT_CLEANUP EvtDeviceContextCleanup;
  17. } // extern "C"
  18. // PnP 回调使用 C++ 链接(WDF 宏内部处理)
  19. EVT_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware;
  20. namespace commkit_driver {
  21. // 全局驱动对象(仅用于内部日志/调试)
  22. static WDFDRIVER g_wdf_driver = nullptr;
  23. } // namespace commkit_driver
  24. extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object,
  25. PUNICODE_STRING registry_path) {
  26. NTSTATUS status;
  27. WDF_DRIVER_CONFIG cfg;
  28. // 初始化全局客户端连接管理器
  29. commkit_driver::GetClientConnection().Initialize();
  30. // 初始化 WDF 配置
  31. WDF_DRIVER_CONFIG_INIT(&cfg, EvtDeviceAdd);
  32. cfg.EvtDriverUnload = EvtDriverUnload;
  33. // 创建 WDF 驱动对象
  34. status = WdfDriverCreate(driver_object, registry_path,
  35. WDF_NO_OBJECT_ATTRIBUTES, &cfg,
  36. &commkit_driver::g_wdf_driver);
  37. if (!NT_SUCCESS(status)) {
  38. return status;
  39. }
  40. // 初始化 ClientConnection(创建控制设备)
  41. status = commkit_driver::CreateControlDevice(commkit_driver::g_wdf_driver);
  42. if (!NT_SUCCESS(status)) {
  43. return status;
  44. }
  45. return STATUS_SUCCESS;
  46. }
  47. extern "C" NTSTATUS EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT init) {
  48. UNREFERENCED_PARAMETER(driver);
  49. NTSTATUS status;
  50. // 1. 标记为过滤设备
  51. WdfFdoInitSetFilter(init);
  52. // 2. 注册 PnP 电源回调(EvtDevicePrepareHardware 解析 COM 编号)
  53. WDF_PNPPOWER_EVENT_CALLBACKS pnp_callbacks;
  54. WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_callbacks);
  55. pnp_callbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware;
  56. WdfDeviceInitSetPnpPowerEventCallbacks(init, &pnp_callbacks);
  57. // 3. 注册 WDM IRP 预处理回调(拦截 READ/WRITE/DEVICE_CONTROL)
  58. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
  59. init, commkit_driver::SerialFilter::DispatchRead,
  60. IRP_MJ_READ, nullptr, 0);
  61. if (!NT_SUCCESS(status)) {
  62. return status;
  63. }
  64. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
  65. init, commkit_driver::SerialFilter::DispatchWrite,
  66. IRP_MJ_WRITE, nullptr, 0);
  67. if (!NT_SUCCESS(status)) {
  68. return status;
  69. }
  70. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
  71. init, commkit_driver::SerialFilter::DispatchDeviceControl,
  72. IRP_MJ_DEVICE_CONTROL, nullptr, 0);
  73. if (!NT_SUCCESS(status)) {
  74. return status;
  75. }
  76. // 4. 创建 WDF 设备
  77. WDFDEVICE device;
  78. WDF_OBJECT_ATTRIBUTES attrs;
  79. WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, DEVICE_CONTEXT);
  80. attrs.EvtCleanupCallback = EvtDeviceContextCleanup;
  81. status = WdfDeviceCreate(&init, &attrs, &device);
  82. if (!NT_SUCCESS(status)) {
  83. return status;
  84. }
  85. // 5. 初始化设备上下文
  86. PDEVICE_CONTEXT ctx = DeviceGetContext(device);
  87. ctx->ComNumber = 0; // 延迟到 EvtDevicePrepareHardware 解析
  88. ctx->MonitoringEnabled = FALSE;
  89. ctx->RingBuffer = nullptr;
  90. ctx->WdfDevice = device;
  91. ctx->LowerDevice = WdfDeviceWdmGetAttachedDevice(device);
  92. // 6. 注册到全局端口表(com_number 暂为 0,PrepareHardware 时更新)
  93. commkit_driver::GetClientConnection().RegisterFilterDevice(device);
  94. return STATUS_SUCCESS;
  95. }
  96. NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
  97. WDFCMRESLIST resources,
  98. WDFCMRESLIST resources_translated) {
  99. UNREFERENCED_PARAMETER(resources);
  100. UNREFERENCED_PARAMETER(resources_translated);
  101. NTSTATUS status;
  102. PDEVICE_CONTEXT ctx = DeviceGetContext(device);
  103. // 从 PnP 属性解析 COM 编号
  104. // 方式:获取 DevicePropertyFriendlyName 或 DevicePropertyDeviceDescription,
  105. // 匹配 "COM%d" 模式
  106. WDFMEMORY memory;
  107. status = WdfDeviceAllocAndQueryProperty(
  108. device, DevicePropertyFriendlyName, NonPagedPoolNx, 0, &memory);
  109. if (!NT_SUCCESS(status)) {
  110. // 尝试 DeviceDescription 作为后备
  111. status = WdfDeviceAllocAndQueryProperty(
  112. device, DevicePropertyDeviceDescription, NonPagedPoolNx, 0, &memory);
  113. }
  114. if (NT_SUCCESS(status)) {
  115. PWCHAR name = (PWCHAR)WdfMemoryGetBuffer(memory, nullptr);
  116. if (name) {
  117. // 解析 "COMx" 模式(可能出现在 "COMx (port)" 或 "通信端口 (COMx)" 等格式中)
  118. ULONG name_len = (ULONG)wcslen(name);
  119. for (ULONG i = 0; i + 3 <= name_len; i++) {
  120. if ((name[i] == L'C' || name[i] == L'c') &&
  121. (name[i+1] == L'O' || name[i+1] == L'o') &&
  122. (name[i+2] == L'M' || name[i+2] == L'm')) {
  123. if (name[i+3] >= L'0' && name[i+3] <= L'9') {
  124. ULONG num = 0;
  125. ULONG j = i + 3;
  126. while (j < name_len && name[j] >= L'0' && name[j] <= L'9') {
  127. num = num * 10 + (name[j] - L'0');
  128. j++;
  129. }
  130. if (num > 0 && num <= 256) {
  131. ctx->ComNumber = num;
  132. break;
  133. }
  134. }
  135. }
  136. }
  137. }
  138. WdfObjectDelete(memory);
  139. }
  140. // 后备方案:FriendlyName/DeviceDescription 均未解析出 COM 编号时,
  141. // 从 PDO 名称查询 HKLM\HARDWARE\DEVICEMAP\SERIALCOMM 获取 "COMx" 映射
  142. if (ctx->ComNumber == 0) {
  143. WDFMEMORY pdo_memory;
  144. status = WdfDeviceAllocAndQueryProperty(
  145. device, DevicePropertyPhysicalDeviceObjectName,
  146. NonPagedPoolNx, 0, &pdo_memory);
  147. if (NT_SUCCESS(status)) {
  148. PWCHAR pdo_name = (PWCHAR)WdfMemoryGetBuffer(pdo_memory, nullptr);
  149. if (pdo_name && pdo_name[0] != L'\0') {
  150. UNICODE_STRING key_path;
  151. RtlInitUnicodeString(&key_path,
  152. L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\SERIALCOMM");
  153. OBJECT_ATTRIBUTES obj_attr;
  154. InitializeObjectAttributes(&obj_attr, &key_path,
  155. OBJ_CASE_INSENSITIVE, nullptr, nullptr);
  156. HANDLE hkey;
  157. status = ZwOpenKey(&hkey, KEY_READ, &obj_attr);
  158. if (NT_SUCCESS(status)) {
  159. UNICODE_STRING value_name;
  160. RtlInitUnicodeString(&value_name, pdo_name);
  161. UCHAR result_buf[256] = {0};
  162. ULONG result_len = 0;
  163. status = ZwQueryValueKey(hkey, &value_name,
  164. KeyValuePartialInformation,
  165. result_buf, sizeof(result_buf), &result_len);
  166. if (NT_SUCCESS(status)) {
  167. KEY_VALUE_PARTIAL_INFORMATION* kv_info =
  168. (KEY_VALUE_PARTIAL_INFORMATION*)result_buf;
  169. if (kv_info->Type == REG_SZ && kv_info->DataLength >= sizeof(WCHAR)) {
  170. PWCHAR com_name = (PWCHAR)kv_info->Data;
  171. ULONG com_len = kv_info->DataLength / sizeof(WCHAR);
  172. // 解析 "COMx"
  173. if (com_len >= 4 &&
  174. (com_name[0] == L'C' || com_name[0] == L'c') &&
  175. (com_name[1] == L'O' || com_name[1] == L'o') &&
  176. (com_name[2] == L'M' || com_name[2] == L'm') &&
  177. com_name[3] >= L'0' && com_name[3] <= L'9') {
  178. ULONG num = 0;
  179. ULONG j = 3;
  180. while (j < com_len &&
  181. com_name[j] >= L'0' && com_name[j] <= L'9') {
  182. num = num * 10 + (com_name[j] - L'0');
  183. j++;
  184. }
  185. if (num > 0 && num <= 256) {
  186. ctx->ComNumber = num;
  187. }
  188. }
  189. }
  190. }
  191. ZwClose(hkey);
  192. }
  193. }
  194. WdfObjectDelete(pdo_memory);
  195. }
  196. }
  197. // 更新端口表中的 COM 编号
  198. commkit_driver::GetClientConnection().UpdatePortComNumber(device, ctx->ComNumber);
  199. return STATUS_SUCCESS;
  200. }
  201. // 设备上下文清理回调:设备移除时注销端口表条目
  202. VOID EvtDeviceContextCleanup(WDFOBJECT object) {
  203. WDFDEVICE device = (WDFDEVICE)object;
  204. PDEVICE_CONTEXT ctx = DeviceGetContext(device);
  205. if (ctx && ctx->ComNumber != 0) {
  206. commkit_driver::GetClientConnection().UnregisterFilterDevice(ctx->ComNumber);
  207. }
  208. }
  209. extern "C" VOID EvtDriverUnload(WDFDRIVER driver) {
  210. UNREFERENCED_PARAMETER(driver);
  211. commkit_driver::GetClientConnection().Cleanup();
  212. commkit_driver::g_wdf_driver = nullptr;
  213. }