Pertanyaan Mendeteksi Kejadian Penyisipan / Penghapusan USB di Windows menggunakan C ++


Saya sedang menulis ekstensi untuk aplikasi yang sudah ada yang perlu menangani peristiwa penyisipan / penghapusan USB. Saya tahu VID / PID dari perangkat yang menarik. Namun, saya tidak memiliki akses ke pegangan jendela, jadi saya tidak tahu RegisterDeviceNotification akan sangat berguna, kecuali ada cara untuk mendapatkan pegangan melalui WINAPI. Apa cara terbaik untuk mendeteksi kejadian penyisipan / penghapusan USB dengan C ++?

Kode contoh ini di situs web Microsoft menunjukkan cara menerima notifikasi acara melalui WMI:

Bagaimana ini bisa dimodifikasi untuk menerima acara penyisipan / penghapusan USB? Atau, apakah ada cara lain yang harus saya lakukan tentang hal ini? Saya menggunakan Visual Studio 2008. Terima kasih.

INFORMASI TAMBAHAN

Inilah yang saya miliki sejauh ini (dikurangi penanganan kesalahan):

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);
}

PC masuk ke dalamnya WndProc, tetapi tidak ketika saya menghapus / memasukkan perangkat USB saya. PC sepertinya tidak pernah masuk ke dalamnya OnDeviceChange. Tips apa pun akan dihargai. Saya perlu menangani penyisipan / penghapusan yang tidak diharapkan dari perangkat USB. Jika itu membuat perbedaan, perangkat USB muncul sebagai port COM virtual ke Windows. Terima kasih.

Info tambahan: Panggilan CreateWindowEx menggunakan kelas atom dikembalikan oleh RegisterClassEx gagal dengan pesan kesalahan, "Tidak dapat menemukan kelas jendela."

_hWnd = CreateWindowEx( 0, (LPCTSTR)&atom, pWindowName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );

PENDEKATAN BARU

Saya juga mencoba pendekatan baru ini. Saya mencoba untuk menulis jendela pesan-saja untuk menerima pesan pemberitahuan perubahan perangkat untuk perangkat USB. Saya menggunakan MFC, C ++, dan Visual Studio 2008. Semuanya mengkompilasi, dan berjalan tanpa menabrak atau mengunci, tetapi pengendali event tidak pernah dipicu. Perangkat yang menarik diinstal pada Windows sebagai port COM virtual.

Aplikasi utama saya instantiate kelas yang dijelaskan di bawah ini kemudian menunggu input karakter dari polling keyboard menggunakan loop sementara. Selama waktu tunggu inilah saya menghapus dan memasukkan perangkat USB saya yang mengharapkan kejadian itu dipecat.

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.
};

Untuk kesederhanaan, saya telah menghapus semua pembersihan dan penanganan kesalahan:

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 );
}

Setiap pemikiran atau saran akan sangat dihargai. Jika ada detail yang hilang, beri tahu saya, dan saya akan senang untuk menambahkannya. Terima kasih.

Apakah jendela pesan-saja harus dimulai di utas baru, atau apakah membuat jendela baru secara otomatis akan memutus utas baru?


20
2017-11-02 14:59


asal


Jawaban:


Buat jendela tiruan yang tidak melakukan apa-apa selain menunggu WM_DEVICECHANGE dan daftarkan jendela itu menggunakan RegisterDeviceNotification. WMI adalah berlebihan di sini, IMHO.


14
2017-11-02 15:06



Ada sebuah Sampel MSDN khusus untuk kasus Anda, dalam kode asli.

Mendaftar untuk Pemberitahuan Perangkat

Lebih baik melakukannya dengan cara ini daripada melalui WMI.


7
2017-11-02 15:15



Saya mengikuti "pendekatan baru" Anda dan juga menemukan bahwa OnDeviceChange tidak dipanggil. Masalahnya adalah tidak ada pengulangan pesan karena itu adalah aplikasi Konsol. Memanggil fungsi berikut pada interval reguler memperbaikinya.

void check_for_device_change()
{
    MSG msg; 

    const int val = PeekMessage( &msg, 0, 0, 0, PM_REMOVE );

    if( val > 0 )
    { 
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    } 
}

6
2017-08-09 10:13