使用 C++ 在 Windows 中检测 USB 插入/移除事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4078909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detecting USB Insertion / Removal Events in Windows using C++
提问by Jim Fell
I am writing an extension for an existing application that needs to handle USB insertion/removal events. I know the VID/PID of the device of interest. However, I don't have access to the window handle, so I don't know if RegisterDeviceNotification
will be of much use, unless there is a way to obtain the handle via the WINAPI
. What would be the best way to detect USB insertion/removal events with C++?
我正在为需要处理 USB 插入/移除事件的现有应用程序编写扩展。我知道感兴趣设备的 VID/PID。但是,我无权访问窗口句柄,所以我不知道是否RegisterDeviceNotification
会有太大用处,除非有办法通过WINAPI
. 使用 C++ 检测 USB 插入/移除事件的最佳方法是什么?
This sample code on the Microsoft websiteshows how to receive event notifications via WMI:
Microsoft 网站上的此示例代码显示了如何通过 WMI 接收事件通知:
How could it be modified to receive USB insertion/removal events? Or, is there another way I should be going about this? I am using Visual Studio 2008. Thanks.
如何修改它以接收 USB 插入/移除事件?或者,我还有其他方法可以解决这个问题吗?我正在使用 Visual Studio 2008。谢谢。
ADDITIONAL INFO
附加信息
This is what I have so far (minus error-handling):
这是我到目前为止所拥有的(减去错误处理):
DEFINE_GUID(GUID_INTERFACE_CP210x, 0x993f7832, 0x6e2d, 0x4a0f, 0xb2, 0x72, 0xe2, 0xc7, 0x8e, 0x74, 0xf9, 0x3e);
MyClass::MyClass()
{
// Generate message-only window
_pWndClassEx = (WNDCLASSEX *)malloc( sizeof(WNDCLASSEX) );
memset( _pWndClassEx, 0, sizeof(WNDCLASSEX) );
_pWndClassEx->cbSize = sizeof(WNDCLASSEX);
_pWndClassEx->lpfnWndProc = (WNDPROC)WndProc; // function which will handle messages
_pWndClassEx->hInstance = GetCurrentModule();
_pWndClassEx->lpszClassName = pClassName;
atom = RegisterClassEx( _pWndClassEx );
_hWnd = CreateWindowEx( 0, pClassName, pWindowName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );
// Register the USB device for notification
_pDevIF = (DEV_BROADCAST_DEVICEINTERFACE *)malloc( sizeof(DEV_BROADCAST_DEVICEINTERFACE) );
memset( _pDevIF, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE) );
_pDevIF->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
_pDevIF->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
_pDevIF->dbcc_classguid = GUID_INTERFACE_CP210x;
_hNotifyDevNode = RegisterDeviceNotification( _hWnd, _pDevIF, DEVICE_NOTIFY_WINDOW_HANDLE );
}
static bool OnDeviceChange(UINT nEventType, DWORD dwData)
{
switch ( nEventType )
{
case DBT_DEVICEARRIVAL:
// A device has been inserted adn is now available.
break;
case DBT_DEVICEREMOVECOMPLETE:
// Device has been removed.
break;
default:
break;
}
return true;
}
static LRESULT WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_DEVICECHANGE:
OnDeviceChange( wParam, lParam ); // Set breakpoint (never gets here)
break;
default:
break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
The PC gets into WndProc
, but not when I remove/insert my USB device. The PC never seems to get into OnDeviceChange
. Any tips would be appreciated. I need to handle unexpected insertions/removals of the USB device. If it makes a difference, the USB device appears as a virtual COM port to Windows. Thanks.
PC 进入WndProc
,但在我移除/插入 USB 设备时不会进入。PC 似乎永远无法进入OnDeviceChange
. 任何提示将不胜感激。我需要处理 USB 设备的意外插入/移除。如果有所不同,USB 设备将作为 Windows 的虚拟 COM 端口出现。谢谢。
Aditional info:Calling CreateWindowEx
using the class atom
returned by RegisterClassEx
fails with the error message, "Cannot find window class."
附加信息:CreateWindowEx
使用atom
返回的类调用RegisterClassEx
失败并显示错误消息“找不到窗口类”。
_hWnd = CreateWindowEx( 0, (LPCTSTR)&atom, pWindowName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );
NEW APPROACH
新的方法
I'm also trying this new approach. I'm trying to get write a message-only window to receive device change notification messages for a USB device. I am using MFC, C++, and Visual Studio 2008. Everything compiles, and it runs without crashing or locking up, but the event handler is never triggered. The device of interest is installed on Windows as a virtual COM port.
我也在尝试这种新方法。我正在尝试编写一个仅消息窗口来接收 USB 设备的设备更改通知消息。我正在使用 MFC、C++ 和 Visual Studio 2008。一切都可以编译,并且它在运行时不会崩溃或锁定,但从未触发事件处理程序。感兴趣的设备作为虚拟 COM 端口安装在 Windows 上。
My main application instantiates the class described below then waits for a character input from the keyboard polling using a while loop. It is during this wait time that I remove and insert my USB device expecting the event to get fired.
我的主应用程序实例化下面描述的类,然后使用 while 循环等待来自键盘轮询的字符输入。正是在这段等待时间内,我移除并插入了我的 USB 设备,期待事件被触发。
class CMessageOnlyWindow : public CWnd
{
DECLARE_DYNAMIC(CMessageOnlyWindow)
private:
DEV_BROADCAST_DEVICEINTERFACE * _pDevIF; // The notification filter.
HDEVNOTIFY _hNotifyDev; // The device notification handle.
public:
CMessageOnlyWindow();
virtual ~CMessageOnlyWindow();
protected:
afx_msg BOOL OnDeviceChange( UINT nEventType, DWORD dwData );
private:
void RegisterNotification( void );
void UnregisterNotification( void );
protected:
DECLARE_MESSAGE_MAP() // Must be last.
};
For simplicity, I've removed all the cleanup and error-handling:
为简单起见,我删除了所有清理和错误处理:
DEFINE_GUID(GUID_INTERFACE_CP210x, 0x993f7832, 0x6e2d, 0x4a0f, \
0xb2, 0x72, 0xe2, 0xc7, 0x8e, 0x74, 0xf9, 0x3e);
IMPLEMENT_DYNAMIC(CMessageOnlyWindow, CWnd)
CMessageOnlyWindow::CMessageOnlyWindow()
{
CString cstrWndClassName = ::AfxRegisterWndClass( NULL );
BOOL bCreated = this->CreateEx( 0, cstrWndClassName,
L"CMessageOnlyWindow", 0, 0, 0, 0, 0, HWND_MESSAGE, 0 );
this->RegisterNotification();
}
CMessageOnlyWindow::~CMessageOnlyWindow() {}
BEGIN_MESSAGE_MAP(CMessageOnlyWindow, CWnd)
ON_WM_DEVICECHANGE()
END_MESSAGE_MAP()
afx_msg BOOL CMessageOnlyWindow::OnDeviceChange( UINT nEventType, DWORD dwData )
{
switch ( nEventType ) // <-- Never gets here.
{
case DBT_DEVICEARRIVAL:
break;
case DBT_DEVICEREMOVECOMPLETE:
break;
default:
break;
}
return TRUE;
}
void CMessageOnlyWindow::RegisterNotification(void)
{
_pDevIF = (DEV_BROADCAST_DEVICEINTERFACE *)malloc( sizeof(DEV_BROADCAST_DEVICEINTERFACE) );
memset( _pDevIF, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE) );
_pDevIF->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
_pDevIF->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
_pDevIF->dbcc_classguid = GUID_INTERFACE_CP210x;
_hNotifyDev = RegisterDeviceNotification( this->m_hWnd, _pDevIF, DEVICE_NOTIFY_WINDOW_HANDLE );
}
void CMessageOnlyWindow::UnregisterNotification(void)
{
UnregisterDeviceNotification( _hNotifyDev );
}
Any thoughts or suggestions would be much appreciated. If any details are missing, let me know, and I will be glad to add them. Thanks.
任何想法或建议将不胜感激。如果缺少任何细节,请告诉我,我会很乐意添加它们。谢谢。
Does the message-only window need to be started in a new thread, or does creating a new window automatically spin off a new thread?
是否需要在新线程中启动仅消息窗口,还是创建新窗口会自动脱离新线程?
采纳答案by kichik
Create a dummy window that does nothing but wait for WM_DEVICECHANGE
and register that window using RegisterDeviceNotification
. WMI is an overkill here, IMHO.
创建一个虚拟窗口,除了等待WM_DEVICECHANGE
并使用RegisterDeviceNotification
. WMI在这里是一种矫枉过正,恕我直言。
回答by Steve Townsend
There is a MSDN samplespecifically for your case, in native code.
有一个专门针对您的案例的MSDN 示例,采用本机代码。
Registering for Device Notification
注册设备通知
Better to do it this way than via WMI.
这样做比通过 WMI 更好。
回答by John W
I followed your "new approach" and also found that OnDeviceChange wasn't being called. The problem was that there was no message loop because it was a Console app. Calling the following function at regular intervals fixed it.
我遵循了您的“新方法”,还发现没有调用 OnDeviceChange。问题是没有消息循环,因为它是一个控制台应用程序。定期调用以下函数修复了它。
void check_for_device_change()
{
MSG msg;
const int val = PeekMessage( &msg, 0, 0, 0, PM_REMOVE );
if( val > 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
回答by jayprakash
This is another way for detecting the INSERTION & REMOVAL of USB storage devices.
这是另一种检测 USB 存储设备插入和移除的方法。
This c++ code detect INSERTION and REMOVAL both of USB Storage devices.
此 C++ 代码检测插入和移除两个 USB 存储设备。
This also detect Multiple insertion and removal of USB devices at same time.
这也会同时检测多个 USB 设备的插入和移除。
c++ code:Tested in VISUAL STUDIO 2015
C++ 代码:在 VISUAL STUDIO 2015 中测试
You can also check for other types of devices for removal and insertion.
Just fill passed char array to other types of devices in if else
of the code in function getUSBStorageDeviceList()
您还可以检查是否有其他类型的设备进行移除和插入。只需if else
在函数getUSBStorageDeviceList()的代码中将传递的字符数组填充到其他类型的设备
#include "stdafx.h"
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <string>
#include<iostream>
using namespace std;
#define MAX_LETTER 26
char PREV_DRIVE_LIST[MAX_LETTER];
char NEW_DRIVE_LIST[MAX_LETTER];
/* To GET DRIVE LIST in char ARRAY */
void getUSBStorageDeviceList(char drive[]) {
int count = 0;
char szLogicalDrives[MAX_PATH];
size_t size = strlen(szLogicalDrives) + 1;
wchar_t* text = new wchar_t[size];
size_t outSize;
mbstowcs_s(&outSize, text, size, szLogicalDrives, size - 1);
DWORD dwResult = GetLogicalDriveStrings(MAX_PATH, text); // text = szLogicalDrives
WCHAR* szSingleDrive = text;
while (*szSingleDrive)
{
UINT nDriveType = GetDriveType(szSingleDrive);
// printf("\nFUNC: getRemovableDisk, Drive Name%d= %s", ++count, szSingleDrive);
if (nDriveType == DRIVE_UNKNOWN) {
// cout << "\nDrive type : Unknown: The drive type cannot be determined." << endl;
}
else if (nDriveType == DRIVE_NO_ROOT_DIR) {
// cout << "\nDrive type : Invalid Root Directory Media: The root path is invalid." << endl;
}
else if (nDriveType == DRIVE_REMOVABLE) {
// cout << "\nDrive type : Removable Media:" << endl;
char letter = szSingleDrive[0];
drive[letter - 65] = letter;
}
else if (nDriveType == DRIVE_FIXED) {
//cout << "\nDrive type : Fixed Media: " << endl;
}
else if (nDriveType == DRIVE_REMOTE) {
//cout << "\nDrive type : Remote Media: The drive is a remote (network) drive.." << endl;
}
else if (nDriveType == DRIVE_CDROM) {
//cout << "\nDrive type : CD ROM: The drive is a CD-ROM drive." << endl;
}
else if (nDriveType == DRIVE_RAMDISK) {
//cout << "\nDrive type : RAM Disk: The drive is a RAM disk." << endl;
}
szSingleDrive += wcslen(szSingleDrive) + 1; // next drive
}
}
int main(void) {
int count = 0;
for (int i = 0; i < MAX_LETTER; i++) {
PREV_DRIVE_LIST[i] = '0';
NEW_DRIVE_LIST[i] = '0';
}
// initial drive list which is already attached
getUSBStorageDeviceList(PREV_DRIVE_LIST);
while (1) {
getUSBStorageDeviceList(NEW_DRIVE_LIST);
count = 1;
/* Check for insertion and removabal*/
for (int i = 0; i < MAX_LETTER; i++) {
// check for new drive
if ((NEW_DRIVE_LIST[i] >= 65 && NEW_DRIVE_LIST[i] <= 89) && (PREV_DRIVE_LIST[i] == '0')) {
printf("\nNew Device Inserted%d : %c", count++, NEW_DRIVE_LIST[i]);
PREV_DRIVE_LIST[i] = NEW_DRIVE_LIST[i];
}
}
// fill ALl zero
for (int i = 0; i < MAX_LETTER; i++) {
NEW_DRIVE_LIST[i] = '0';
}
// update NEW drive list
getUSBStorageDeviceList(NEW_DRIVE_LIST);
for (int i = 0; i < MAX_LETTER; i++) {
// check for removed drive
if ((PREV_DRIVE_LIST[i] >= 65 && PREV_DRIVE_LIST[i] <= 89) && (NEW_DRIVE_LIST[i] == '0')) {
printf("\nDevice Removed%d : %c", count++, PREV_DRIVE_LIST[i]);
PREV_DRIVE_LIST[i] = NEW_DRIVE_LIST[i];
}
}
Sleep(500);
}
return 0;
}
REMARK :This does not create Any windows. This is console Application.
备注:这不会创建任何窗口。这是控制台应用程序。