USB Win Events messages Detecting in QT
Hello all,
I have been searching through the QT Assistant and the forums here on events and processing them. I am working on an application where I need to detect when the VID/PID of the device is attached/detached to/from the system. From what I have discovered so far, it would appear as though I can create a class using a QAbstractEventDispatcher and an event filter function referencing a pointer to the received message. Which in the implementation would set the instance thread to 0, i.e. m_EvtDispatch = QAbstractEventDispatcher::instance(0);" and then set event filter, "m_EvtDispatch->setEventFilter(myClass::myEventFilter);"
For the function implementation, it would process the message, maybe as a MSG type (unsure). I have a sample I am working with now as described, and the myEvent loop activates, but the parameters don't seem to ever match DBT_DEVICEARRIVAL/DBT_DEVICEREMOVECOMPLETE/or even DBT_DEVNODES_CHANGED, from the WM_DEVICECHANGE message.
I have searched through the QEvent and QActionEvent and multiple others looking for something close on searching for new devices, but I am kind of at a loss. Any help would be greatly appreciated.
Thanks,
Alphawolfxv
[EDIT 2008-Aug-14]: Should have noted system parameters, QT4.3.3, Win Vista.
[EDIT 2008-Aug-14]: Added code sample.
All these files are trying to do is to break when the WM_DEVICECHANGE is received, I can look for the Attach/Detach once this step is complete, I hope... :o
Header:
Code:
#ifndef TESTMSG1_H
#define TESTMSG1_H
#include <QtGui/QDialog>
#include <QAbstractEventDispatcher>
#include <QtDebug>
#include <windows.h>
#include <dbt.h>
{
Q_OBJECT
public:
~TestMsg();
static bool myEvtFilter(void *message);
private:
};
#endif // TESTMSG1_H
Implementation:
Code:
#include "testmsg1.h"
bool TestMsg::myEvtFilter(void *message)
{
MSG *msg;
static int i = 0;
msg = (MSG*)message;
qDebug() << "Test that we are getting events...";
qDebug() << "message: " << msg->message << " wParam: " << msg->wParam
<< " lParam: " << msg->lParam << " handle: " << msg->hwnd;
if (msg->message == WM_DEVICECHANGE)
{
i++;
qDebug() << "Count:" << i << "wParam:" << msg->wParam << "lParam:" << msg-> lParam;
}
return false;
}
{
m_EvtDispatch->setEventFilter(TestMsg::myEvtFilter);
}
TestMsg::~TestMsg()
{
}
Re: USB Win Events messages Detecting in QT
I have also tried to install an event filter for CD arrival notification and could not
get it to work. Here is what i did :
_________ MFrame.h_________________
Code:
#include <qt_windows.h>
{
Q_OBJECT
public:
MFrame();
protected :
bool winEvent(MSG *msg,long * result);
signals:
void CD_Removed
(QChar tchar
);
void CD_Arrived
(QChar tchar
);
};
________ MFrame.cpp ____________________
Code:
#include <QtCore>
#include <QtGui>
#include <QtDebug>
#include "mframe.h"
#include <dbt.h>
static char FirstDriveFromMask (ULONG unitmask)
{
char i;
for (i = 0; i < 26; ++i)
{
if (unitmask & 0x1)
break;
unitmask = unitmask >> 1;
}
return (i + 'A');
}
bool MFrame::winEvent(MSG * msg, long * result)
{
int msgType = msg->message;
if(msgType == WM_DEVICECHANGE)
{
qDebug() << "winEvent in MgFrame : WM_DEVICECHANGE" ;
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
switch(msg->wParam)
{
case DBT_DEVICEARRIVAL:
if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
if (lpdbv -> dbcv_flags & DBTF_MEDIA)
{
char ALET = FirstDriveFromMask(lpdbv->dbcv_unitmask);
emit CD_Arrived
(QChar(ALET
));
qDebug() << "CD_Arrived ";
}
}
break;
case DBT_DEVICEREMOVECOMPLETE:
if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
if (lpdbv -> dbcv_flags & DBTF_MEDIA)
{
char ALET = FirstDriveFromMask(lpdbv->dbcv_unitmask);
emit CD_Removed
(QChar(ALET
));
qDebug() << "CD_Removed";
}
}
break;
} // skip the rest
} // end of if msgType
return false; // let qt handle the rest
}
I found that It only works on the main window. This is why I emit CD_Arrived and
CD_Removed signals.
Hope this helps
Murielle
Re: USB Win Events messages Detecting in QT
Murielle,
Thank you so very much. I am able to now at least detect when the change happens! I can filter through the rest of the necessary parameters for VID/PID now that I have a starting point! Thanks again for the great example!! :)
Cyrus
Re: USB Win Events messages Detecting in QT
It's been a while since the original post, but I encountered the same problem and here is how i solved it:
1. How to recognize if an USB drive is plugged in or out:
- inclde the following headers: #include <windows.h> #include <Dbt.h> #include <SetupAPI.h>
- register this function in your GUI class header filer under public: bool winEvent ( MSG * msg, long * result );
- also define the char variable DriveLetter there: char DriveLetter;
- in your GUI class cpp-file this function shoud be definde like this:
bool myGUI::winEvent(MSG *msg, long *result)
{
int msgType = msg->message;
if(msgType == WM_DEVICECHANGE)
{
switch(msg->wParam)
{
case DBT_DEVICEARRIVAL:
getDriveLetterFromMsg(msg);
getMoreDriveInfosFromLetter(DriveLetter);
break;
case DBT_DEVICEREMOVECOMPLETE:
getDriveLetterFromMsg(msg);
break;
}
}
return false;
}
2. What you now need are the functions getDriveLetterFromMsg(msg) and getMoreDriveInfosFromLetter(DriveLetter). Here they are:
- char getDriveLetterFromMsg(MSG *msg)
{
char DriveLetter = 0;
PDEV_BROADCAST_HDR drive_hdr = (PDEV_BROADCAST_HDR)msg->lParam;
if (drive_hdr -> dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME volume_hdr = (PDEV_BROADCAST_VOLUME)drive_hdr;
PDEV_BROADCAST_DEVICEINTERFACE device_info = (PDEV_BROADCAST_DEVICEINTERFACE)drive_hdr;
char name = (char)device_info->dbcc_name;
DriveLetter = FirstDriveFromMask(volume_hdr->dbcv_unitmask);
}
return DriveLetter;
} - bool getMoreDriveInfosFromLetter(char driveletter, mydrive *drive){
//catch errors
DWORD ercode;
//create Path
std::wstring drivePath_str( L"X:\\" );
std::wstring drivePath_str_UNC( L"\\\\.\\X:" );
drivePath_str[0] = driveletter;
drivePath_str_UNC[4] = driveletter;
const wchar_t* drivePath_chr = drivePath_str.c_str();
const wchar_t* drivePath_chr_UNC = drivePath_str_UNC.c_str();
//get Drive Type
UINT DriveType = GetDriveType((LPCWSTR)drivePath_chr);
ercode = GetLastError();
if(ercode > 0){ tools::writeError(ercode); return false; }
//get Device Number
HANDLE DriveHandle = CreateFile((LPCTSTR)drivePath_chr_UNC,GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE ,NULL, OPEN_EXISTING, 0, NULL);
STORAGE_DEVICE_NUMBER storageDeviceNumber;
DWORD BytesReturned = 0;
DeviceIoControl(DriveHandle,IOCTL_STORAGE_GET_DEVI CE_NUMBER,NULL, 0, &storageDeviceNumber, sizeof(storageDeviceNumber),&BytesReturned, NULL);
ercode = GetLastError();
if(ercode > 0){ tools::writeError(ercode); return false; }
unsigned long DeviceNumber = storageDeviceNumber.DeviceNumber;
//get more Infos
QString driveInfos = GetDrivesDevInstByDiskNumber(DeviceNumber,DriveTyp e);
if(driveInfos.isEmpty())
{
tools::writeError(QString("Can't get Infos of Drive %1").arg(driveletter));
return false;
}
//save Infos: All the Information gathered is stored in 'driveInfos'
//do something with driveInfos
//everything went ok
return true;
}
3. In addition you need the functions FirstDriveFromMask(volume_hdr->dbcv_unitmask) and GetDrivesDevInstByDiskNumber(long DiskNumber, UINT DriveType):
- char FirstDriveFromMask( ULONG unitmask ){
char i;
for (i = 0; i < 26; ++i){
if (unitmask & 0x1)
break;
unitmask = unitmask >> 1;
}
return( i + 'A' );
} - QString GetDrivesDevInstByDiskNumber(long DiskNumber, UINT DriveType)
{
GUID* guid;
QString DriveInfos;
switch (DriveType)
{
case DRIVE_REMOVABLE:
case DRIVE_FIXED:
guid = (GUID*)(void*)&GUID_DEVINTERFACE_DISK;
break;
case DRIVE_CDROM:
guid = (GUID*)(void*)&GUID_DEVINTERFACE_CDROM;
break;
default:
return 0;
}
// Get device interface info set handle for all devices attached to system
HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
return 0;
}
SP_DEVICE_INTERFACE_DATA devInterfaceData = {0};
BOOL bRet = FALSE;
BYTE Buf[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
SP_DEVICE_INTERFACE_DATA spdid;
SP_DEVINFO_DATA spdd;
DWORD dwSize;
devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
spdid.cbSize = sizeof(spdid);
for(DWORD dwIndex = 0; TRUE; dwIndex++)
{
bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, dwIndex, &devInterfaceData);
if (!bRet)
break;
SetupDiEnumInterfaceDevice(hDevInfo, NULL, guid, dwIndex, &spdid);
dwSize = 0;
SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL);
if ( dwSize!=0 && dwSize<=sizeof(Buf) )
{
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
ZeroMemory((PVOID)&spdd, sizeof(spdd));
spdd.cbSize = sizeof(spdd);
long res = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd, dwSize, &dwSize, &spdd);
if ( res )
{
HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
if ( hDrive != INVALID_HANDLE_VALUE )
{
STORAGE_DEVICE_NUMBER sdn;
DWORD dwBytesReturned = 0;
res = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
CloseHandle(hDrive);
if (res && (DiskNumber == (long)sdn.DeviceNumber))
{
DriveInfos = QString::fromWCharArray(pspdidd->DevicePath);
break;
}
}
}
}
}
SetupDiDestroyDeviceInfoList(hDevInfo);
return DriveInfos;
}