-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDeviceMonitor.cpp
More file actions
544 lines (465 loc) · 13.2 KB
/
DeviceMonitor.cpp
File metadata and controls
544 lines (465 loc) · 13.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
#include "DeviceMonitor.h"
#include "DeviceUtils.h"
#include "DiskMonitor.h"
#include "Shlwapi.h"
#include <algorithm>
#include <stdexcept>
#include <winioctl.h>
using namespace std;
using namespace DeviceUtils;
#pragma comment(lib, "Shlwapi.lib")
DeviceMonitor::DeviceMonitor()
: m_stopWork(FALSE),
m_windowManager(make_unique<WindowManager>(this)) {
}
DeviceMonitor::~DeviceMonitor() {
StopMonitor();
}
bool DeviceMonitor::StartMonitor(std::wstring driveLetters, SpecifiedMode specifiedMode) {
m_stopWork = FALSE;
m_specifiedMode = specifiedMode;
try {
m_windowManager->InitDeviceNotification();
wprintf(L"设备通知初始化成功\n");
}
catch (const exception& e) {
wprintf(L"初始化设备通知失败: %S\n", e.what());
return false;
}
WORD oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
if (specifiedMode == SM_ALL) {
m_specifiedMode = SM_EXCLUDE;
m_specifiedDisk = L""; // 排除空列表=监控所有
wprintf(L"模式:监控所有可用磁盘\n");
}
else {
// 清理输入盘符
m_specifiedDisk.clear();
for (wchar_t c : driveLetters) {
wchar_t upper = towupper(c);
if (upper >= L'A' && upper <= L'Z') {
m_specifiedDisk.push_back(upper);
}
}
wprintf(L"模式:%s,目标盘符:%s\n",
specifiedMode == SM_INCLUDE ? L"包含" : L"排除",
m_specifiedDisk.c_str());
}
// 获取当前所有盘符
wstring currentDrives = GetCurrentDrives();
wprintf(L"当前可用盘符:%s\n", currentDrives.empty() ? L"无" : currentDrives.c_str());
// 根据模式计算需要监控的目标盘符
wstring targetDrives;
switch (m_specifiedMode) {
case SM_INCLUDE:
// 仅监控指定盘符中存在的部分
for (wchar_t c : m_specifiedDisk) {
if (currentDrives.find(c) != wstring::npos) {
targetDrives.push_back(c);
}
}
break;
case SM_EXCLUDE:
// 监控当前盘符中不在排除列表的部分
for (wchar_t c : currentDrives) {
if (m_specifiedDisk.find(c) == wstring::npos) {
targetDrives.push_back(c);
}
}
break;
}
// 初始化目标盘符的监控
if (targetDrives.empty()) {
wprintf(L"无符合条件的磁盘可监控\n");
SetErrorMode(oldErrorMode);
return false;
}
for (wchar_t c : targetDrives) {
if (!InitSingleDiskMonitoring(c)) {
wprintf(L"警告:无法监控磁盘 %c\n", c);
}
}
SetErrorMode(oldErrorMode);
// 检查是否有成功监控的设备
bool hasMonitored = false;
{
lock_guard<mutex> lock(m_devicesMutex);
for (const auto& device : m_devices) {
if (device && device->IsMonitoring()) {
hasMonitored = true;
break;
}
}
}
if (!hasMonitored) {
wprintf(L"没有可监控的磁盘(请检查磁盘是否正常挂载)\n");
return false;
}
wprintf(L"\n等待设备事件...(输入q停止监控)\n");
return true;
}
void DeviceMonitor::StopMonitor() {
if (m_stopWork) return;
m_stopWork = TRUE;
UninitAllDisksMonitoring();
wprintf(L"所有监控已停止\n");
}
void DeviceMonitor::InitAllDisksMonitoring() {
auto currentDrives = GetCurrentDrives();
WORD oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
for (wchar_t c : currentDrives) {
InitSingleDiskMonitoring(c);
}
SetErrorMode(oldErrorMode);
}
bool DeviceMonitor::InitSingleDiskMonitoring(wchar_t driveLetter) {
wstring diskPath = RootPath(driveLetter);
wprintf(L"\n");
// 检查磁盘是否已监控
if (IsDiskMonitored(driveLetter)) {
wprintf(L"磁盘 %c 已在监控中\n", driveLetter);
return true;
}
// 检查路径有效性
if (!PathIsDirectoryW(diskPath.c_str())) {
wprintf(L"路径 %s 不是有效的目录\n", diskPath.c_str());
return false;
}
bool isRemovable = DeviceUtils::IsRemovableDrive(driveLetter);
UINT sysDriveType = GetDriveType(diskPath.c_str()); // 系统定义的驱动器类型
wprintf(L"DeviceMonitor: 磁盘 %s 类型信息\n", diskPath.c_str());
wprintf(L" - 系统定义类型: %d USB设备: %s\n", sysDriveType, isRemovable ? L"是" : L"否");
// 创建设备监控实例
auto device = make_shared<DiskMonitor>();
if (!device->FromDeviceLetter(driveLetter)) {
wprintf(L"初始化设备监控实例失败: %s\n", diskPath.c_str());
return false;
}
// 同时设置两种类型到DiskMonitor
device->SetDriveType(sysDriveType); // 系统定义类型
device->SetIsRemovable(isRemovable);
// 获取并设置设备实例ID
device->SetInstanceId(DeviceUtils::GetInstanceId(diskPath));
wprintf(L" - 设备实例ID: %s\n", device->GetInstanceId().c_str());
// 记录插入时间
FILETIME insertionTime;
GetSystemTimeAsFileTime(&insertionTime);
device->SetInsertionTime(insertionTime);
// 为可移动设备注册通知
HDEVNOTIFY hNotify = NULL;
if (isRemovable) {
hNotify = RegisterRemovableDeviceNotification(driveLetter, device);
device->SetNotifyHandle(hNotify);
}
// 添加到设备列表
{
lock_guard<mutex> lock(m_devicesMutex);
m_devices.push_back(device);
}
// 启动监控
return device->StartMonitoring();
}
void DeviceMonitor::UninitAllDisksMonitoring() {
vector<shared_ptr<DiskMonitor>> devicesCopy;
{
lock_guard<mutex> lock(m_devicesMutex);
devicesCopy = m_devices;
}
for (const auto& device : devicesCopy) {
UninitSingleDevice(device, true);
}
lock_guard<mutex> lock(m_devicesMutex);
m_devices.clear();
}
void DeviceMonitor::UninitSingleDevice(const shared_ptr<DiskMonitor>& device, bool removeFromList) {
if (!device) return;
device->StopMonitoring();
HDEVNOTIFY hNotify = device->GetNotifyHandle();
if (hNotify) {
::UnregisterDeviceNotification(hNotify);
device->SetNotifyHandle(NULL);
}
HANDLE hDevice = device->GetDeviceHandle();
if (hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(hDevice);
device->SetDeviceHandle(INVALID_HANDLE_VALUE);
}
// 从列表移除
if (removeFromList) {
auto it = find_if(m_devices.begin(), m_devices.end(),
[&](const shared_ptr<DiskMonitor>& d) {
return d->GetDriveLetter() == device->GetDriveLetter();
});
if (it != m_devices.end()) {
m_devices.erase(it);
}
}
}
// 判断指定盘符是否需要监控
bool DeviceMonitor::NeedMonitor(wchar_t driveLetter) {
// 统一转换为大写字母,确保判断一致性
wchar_t upperLetter = towupper(driveLetter);
if (upperLetter < L'A' || upperLetter > L'Z') {
wprintf(L"无效盘符: %c,无需监控\n", driveLetter);
return false;
}
// 根据当前模式判断是否需要监控
switch (m_specifiedMode) {
case SM_ALL:
return true;
case SM_INCLUDE:
return (m_specifiedDisk.find(upperLetter) != wstring::npos);
case SM_EXCLUDE:
return (m_specifiedDisk.find(upperLetter) == wstring::npos);
default:
wprintf(L"未知模式,默认不监控盘符: %c\n", upperLetter);
return false;
}
}
wstring DeviceMonitor::GetCurrentDrives() {
wstring driveLetters;
DWORD logicalDrives = GetLogicalDrives();
if (logicalDrives == 0) return driveLetters;
// 遍历A-Z盘符,拼接存在的盘符字母
for (wchar_t letter = L'A'; letter <= L'Z'; ++letter) {
if (logicalDrives & (1 << (letter - L'A'))) {
wstring drivePath = DeviceUtils::RootPath(letter);
if (PathFileExistsW(drivePath.c_str())) {
driveLetters.push_back(letter);
}
}
}
return driveLetters;
}
bool DeviceMonitor::IsDiskMonitored(wchar_t driveLetter) {
lock_guard<mutex> lock(m_devicesMutex);
for (const auto& device : m_devices) {
if (device->GetDriveLetter() == driveLetter && device->IsMonitoring()) {
return true;
}
}
return false;
}
HDEVNOTIFY DeviceMonitor::RegisterRemovableDeviceNotification(wchar_t driveLetter, shared_ptr<DiskMonitor> device) {
// 仅为可移动设备注册额外通知
HANDLE hDevice = CreateFile(
DeviceUtils::RootPath(driveLetter).c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hDevice == INVALID_HANDLE_VALUE) {
wprintf(L"打开设备失败,错误码: %d\n", GetLastError());
return NULL;
}
// 保存设备句柄到DiskMonitor实例
device->SetDeviceHandle(hDevice);
DEV_BROADCAST_HANDLE notifyFilter = { 0 };
notifyFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
notifyFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
notifyFilter.dbch_handle = hDevice;
HDEVNOTIFY hNotify = RegisterDeviceNotification(
m_windowManager->GetHwnd(), // 使用窗口管理器的窗口句柄
¬ifyFilter,
DEVICE_NOTIFY_WINDOW_HANDLE
);
if (!hNotify) {
wprintf(L"注册设备通知失败,错误码: %d\n", GetLastError());
// 如果注册失败,需要关闭已经打开的句柄
CloseHandle(hDevice);
device->SetDeviceHandle(INVALID_HANDLE_VALUE);
}
return hNotify;
}
BOOL DeviceMonitor::HandleDeviceChange(UINT eventType, LPARAM lParam) {
if (eventType == DBT_DEVICEARRIVAL) return OnDeviceArrival(lParam);
else if (eventType == DBT_DEVICEQUERYREMOVE) return OnDeviceQueryRemove(lParam);
else if (eventType == DBT_DEVICEREMOVECOMPLETE) return OnDeviceRemoved(lParam);
return TRUE;
}
BOOL DeviceMonitor::OnDeviceArrival(LPARAM lParam) {
PDEV_BROADCAST_DEVICEINTERFACE pInf = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
std::wstring drive = DeviceUtils::FromInstanceId(pInf->dbcc_name);
wprintf(L"\n");
wprintf(L"===== 检测到设备插入 =====\n");
wprintf(L"dbcc_name: %s\n", pInf->dbcc_name);
if (!drive.empty()) {
for (wchar_t driveLetter : drive) {
if (NeedMonitor(driveLetter)) {
InitSingleDiskMonitoring(driveLetter);
}
}
}
// 获取当前所有可用盘符
auto currentDrives = GetCurrentDrives();
if (currentDrives.empty()) {
wprintf(L"未检测到任何可用盘符\n");
return TRUE;
}
// 获取当前已监控的盘符
wstring monitoredDrives;
{
lock_guard<mutex> lock(m_devicesMutex);
for (const auto& device : m_devices) {
monitoredDrives += device->GetDriveLetter();
}
}
// 对比找出新插入的盘符
wstring newDrives;
for (const auto& curr : currentDrives) {
bool isNew = true;
for (const auto& monitored : monitoredDrives) {
if (curr == monitored) {
isNew = false;
break;
}
}
if (isNew) {
newDrives.push_back(curr);
}
}
// 处理新发现的盘符
if (newDrives.empty()) {
return TRUE;
}
for (wchar_t newDrive : newDrives) {
if (NeedMonitor(newDrive)) {
InitSingleDiskMonitoring(newDrive);
}
}
return TRUE;
}
BOOL DeviceMonitor::OnDeviceQueryRemove(LPARAM lParam) {
wprintf(L"\n===== 检测到设备弹出请求 =====\n");
// 停止对应设备的监控
auto pDevHandle = (PDEV_BROADCAST_HANDLE)lParam;
lock_guard<mutex> lock(m_devicesMutex);
for (const auto& device : m_devices) {
if (device->GetDeviceHandle() == pDevHandle->dbch_handle) {
UninitSingleDevice(device, false);
}
}
return TRUE;
}
BOOL DeviceMonitor::OnDeviceRemoved(LPARAM lParam) {
PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;
if (!pHdr) {
return TRUE;
}
bool handled = false;
vector<shared_ptr<DiskMonitor>> devicesToRemove;
auto currentDrives = GetCurrentDrives();
if (pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
wprintf(L"\n===== 检测到设备移除 =====");
// 查找已知的已移除设备
auto pInf = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
auto instanceId = (wstring)L"\\\\?\\" + DeviceUtils::ParseUsbStoragePath(pInf->dbcc_name);
shared_ptr<DiskMonitor> removedDevice;
{
lock_guard<mutex> lock(m_devicesMutex);
for (const auto& device : m_devices) {
if (device->GetInstanceId() == instanceId) {
removedDevice = device;
break;
}
}
if (removedDevice) {
wprintf(L"\n已移除设备: %c(可移动设备: %s)",
removedDevice->GetDriveLetter(),
removedDevice->IsRemovable() ? L"是" : L"否");
UninitSingleDevice(removedDevice, true);
handled = true;
}
for (const auto& device : m_devices) {
bool exists = false;
for (wchar_t c : currentDrives) {
if (device->GetDriveLetter() == c) {
exists = true;
break;
}
}
if (!exists) {
devicesToRemove.push_back(device);
}
}
if (!devicesToRemove.empty()) {
for (const auto& device : devicesToRemove) {
wprintf(L"\n已移除设备: %c(可移动设备: %s)",
device->GetDriveLetter(),
device->IsRemovable() ? L"是" : L"否");
UninitSingleDevice(device, true);
handled = true;
}
}
}
}
if (handled) {
wprintf(L"\n");
}
return TRUE;
}
shared_ptr<DiskMonitor> DeviceMonitor::FindDeviceByHandleInDev(PDEV_BROADCAST_HANDLE pDevHandle) {
lock_guard<mutex> lock(m_devicesMutex);
for (const auto& device : m_devices) {
if (device->GetDevHandle() && device->GetDevHandle()->dbch_handle == pDevHandle->dbch_handle) {
return device;
}
}
return nullptr;
}
wstring DeviceMonitor::GetFixedDrives() {
wstring result;
lock_guard<mutex> lock(m_devicesMutex);
for (const auto& device : m_devices) {
if (!device->IsRemovable()) {
result += device->GetDriveLetter();
}
}
return result;
}
wstring DeviceMonitor::GetRemovableDrives() {
wstring result;
lock_guard<mutex> lock(m_devicesMutex);
for (const auto& device : m_devices) {
if (device->IsRemovable()) {
result += device->GetDriveLetter();
}
}
return result;
}
DWORD WINAPI DeviceMonitor::AsyncPostQueryRemoveHandler(LPVOID lpParam) {
DeviceMonitor* pThis = static_cast<DeviceMonitor*>(lpParam);
if (!pThis) return 1;
wprintf(L"等待1000ms后重新读取盘符并初始化监控...\n");
Sleep(1000);
// 获取当前可用盘符并重新初始化
auto currentDrives = pThis->GetCurrentDrives();
wprintf(L"重新读取盘符完成,当前有效盘符: %d 个\n", (int)currentDrives.size());
if (!currentDrives.empty()) {
wprintf(L"开始重新初始化磁盘监控...\n");
pThis->InitAllDisksMonitoring();
bool hasMonitored = false;
{
lock_guard<mutex> lock(pThis->m_devicesMutex);
for (const auto& device : pThis->m_devices) {
if (device->IsMonitoring()) {
hasMonitored = true;
break;
}
}
}
if (hasMonitored) {
wprintf(L"磁盘监控重新初始化完成\n");
}
else {
wprintf(L"重新初始化后没有可监控的磁盘\n");
}
}
else {
wprintf(L"没有检测到可用磁盘,无需重新初始化\n");
}
return 0;
}