16

I want to detect insertion/removal of a specific (Custom) USB device through a C++ application which runs in background and has no GUI.

I have seen lot of questions and their solutions RegisterDeviceNotification also sample code on MSDN

But these all application has Some Window/Form/GUI. My Application doesn't have any. How can I use this in my application?

My last option would be to create an invisible window... But is there any other way out??

asked Apr 25, 2013 at 12:26
7
  • Do you want your code to be portable across various OSes? Commented Apr 25, 2013 at 12:29
  • Only Windows... But Yes, Windows XP to Windows 7 (or maybe Win 8 too!) Commented Apr 25, 2013 at 12:31
  • 1
    Create invisible window and handle notification message in its window procedure. You need to make this in a separate thread containing message loop. Commented Apr 25, 2013 at 12:34
  • look here msdn.microsoft.com/en-us/library/windows/desktop/… as it states: "...messages sent to windows..." Commented Apr 25, 2013 at 12:39
  • It does sound like you actually want a "Service", rather than an application, in which case you can pass a "Service status handle" instead of a "HWND" to theRegisterDeviceNotification Commented Apr 25, 2013 at 12:41

5 Answers 5

6
#define ANSI
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <winuser.h>
#include <initguid.h>
#include <usbiodef.h>
#include <Dbt.h>
#include <string>
#include <iostream>
#include <stdexcept>
#define HID_CLASSGUID {0x4d1e55b2, 0xf16f, 0x11cf,{ 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30}}
#define CLS_NAME "DUMMY_CLASS"
#define HWND_MESSAGE ((HWND)-3)
LRESULT message_handler(HWND__* hwnd, UINT uint, WPARAM wparam, LPARAM lparam)
{
 switch (uint)
 {
 case WM_NCCREATE: // before window creation
 return true;
 break;
 case WM_CREATE: // the actual creation of the window
 {
 // you can get your creation params here..like GUID..
 LPCREATESTRUCT params = (LPCREATESTRUCT) lparam;
 GUID InterfaceClassGuid = *((GUID*)params->lpCreateParams);
 DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
 ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
 NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
 NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
 memcpy(&(NotificationFilter.dbcc_classguid),&(GUID_DEVINTERFACE_USB_DEVICE), sizeof(struct _GUID));
 HDEVNOTIFY dev_notify = RegisterDeviceNotification(hwnd, &NotificationFilter,
 DEVICE_NOTIFY_WINDOW_HANDLE);
 if(dev_notify == NULL)
 {
 throw std::runtime_error("Could not register for devicenotifications!");
 }
 break;
 }
 case WM_DEVICECHANGE:
 {
 PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lparam;
 PDEV_BROADCAST_DEVICEINTERFACE lpdbv = (PDEV_BROADCAST_DEVICEINTERFACE) lpdb;
 std::string path;
 if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
 {
 path = std::string(lpdbv->dbcc_name);
 switch (wparam)
 {
 case DBT_DEVICEARRIVAL:
 std::cout << "new device connected: " << path << "\n";
 break;
 case DBT_DEVICEREMOVECOMPLETE:
 std::cout << "device disconnected: " << path << "\n";
 break;
 }
 }
 break;
 }
 }
 return 0L;
}
int main(int argc, char* argv[])
{
 HWND hWnd = NULL;
 WNDCLASSEX wx;
 ZeroMemory(&wx, sizeof(wx));
 wx.cbSize = sizeof(WNDCLASSEX);
 wx.lpfnWndProc = reinterpret_cast<WNDPROC>(message_handler);
 wx.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0));
 wx.style = CS_HREDRAW | CS_VREDRAW;
 wx.hInstance = GetModuleHandle(0);
 wx.hbrBackground = (HBRUSH)(COLOR_WINDOW);
 wx.lpszClassName = CLS_NAME;
 GUID guid = HID_CLASSGUID;
 if (RegisterClassEx(&wx))
 {
 hWnd = CreateWindow(CLS_NAME, "DevNotifWnd", WS_ICONIC,
 0, 0, CW_USEDEFAULT, 0, HWND_MESSAGE,
 NULL, GetModuleHandle(0), (void*)&guid);
 }
 if(hWnd == NULL)
 {
 throw std::runtime_error("Could not create message window!");
 }
 std::cout << "waiting for new devices..\n";
 MSG msg;
 while (GetMessage(&msg, NULL, 0, 0))
 {
 TranslateMessage(&msg);
 DispatchMessage(&msg);
 }
 return 0;
}

This simple program creates a non-visible window and its message handler also receives notifications for 'RegisterDeviceNotification'.

Please make sure to link your program against user32.lib, e.g. /link user32.lib.

(Updated based on below comments from @DerekLu and @Michael Sohnen)

answered Aug 31, 2013 at 23:26
Sign up to request clarification or add additional context in comments.

4 Comments

It doesn't working now. It shows only 'waiting for new devices...'
Please remind users of this code to link user32.lib; Use: "cl.exe code_snippet.cpp /link user32.lib"
@Eric We need to change NotificationFilter.dbcc_classguid = InterfaceClassGuid to memcpy(&(NotificationFilter.dbcc_classguid),&(GUID_DEVINTERFACE_USB_DEVICE), sizeof(struct _GUID)); . And include initguid.h and usbiodef.h FYI: github.com/microsoft/Windows-driver-samples/blob/…
Thanks MichaelSohnen and DerekLu: I updated the original reply using your feedback!
5

Create a message-only window. Despite the name, it's really only a message queue.

answered Apr 25, 2013 at 12:51

4 Comments

@DavidHeffernan: depends on the dbch_devicetype, but the messages for which you need RegisterDeviceNotification aren't broadcast (that's the whole point of the function, after all).
@DavidHeffernan: Not the broadcast ones, no. But for a custom device, I don't expect broadcast messages anyway. They use pub/sub instead of broadcast.
OK, I'm not sure of myself any more. Using a normal window appeared to solve the question here (stackoverflow.com/questions/22016259/…) but I'm not sure why. I think I will delete my comments here because I'm on shaky ground.
Message only windows don't receive broadcast messages. - link
5

External USB Storage Device Detector


This simple C++ code can detect any pen drive, memory card & external hard drive-

#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <string>
using namespace std;
string allDrives;
char getRemovableDisk();
int main(void) {
 char driveLetter = getRemovableDisk();
 while (1) {
 driveLetter = getRemovableDisk();
 if (driveLetter != '0') {
 printf("%c \n", driveLetter);
 }
 Sleep(1000);
 }
 return 0;
}
char getRemovableDisk() {
 char drive = '0';
 char szLogicalDrives[MAX_PATH];
 DWORD dwResult = GetLogicalDriveStrings(MAX_PATH, szLogicalDrives);
 string currentDrives = "";
 //cout << dwResult << endl;
 for (int i = 0; i < dwResult; i++) {
 if (szLogicalDrives[i] > 64 && szLogicalDrives[i] < 90) {
 currentDrives.append(1, szLogicalDrives[i]);
 if (allDrives.find(szLogicalDrives[i]) > 100) {
 drive = szLogicalDrives[i];
 }
 }
 }
 allDrives = currentDrives;
 return drive;
}

PS: This code snippet can detect the insertion of one new USB storage device for Windows OS. If multiple devices are inserted simultaneously in 1 second then only one will be detected. But, of course, you can achieve multiple detections too with a little code change. :)

answered Nov 22, 2015 at 16:07

1 Comment

This will work only for USB storage devices, not for other types like HID
2

This c++ code detect INSERTION and REMOVAL both of USB Storage devices.

This also detect Multiple insertion and removal of USB devices at same time.

c++ code: Tested in 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()

 #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;
 }
answered Feb 25, 2020 at 11:00

Comments

0

Create a service first and in RegisterDeviceNotification, give the handle of that service instead of a window handle.

Also adjust the third parameter of RegisterDeviceNotification accordingly.

answered May 28, 2013 at 18:13

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.