qt main 函式的幾個實用性的做法(包括單啟動、檢測usb接入事件)
1、QApplication::addLibraryPath()新增庫檔案路徑。
2、Qt中實現單啟動 QSharedMemory (The QSharedMemory class provides access to a shared memory segment.),呼叫create()函式,通過其返回值來判斷程式是否申請過該記憶體,若申請過則可判斷程式已經啟動,從而退出程式。
3、Q_INIT_RESOURCE(name),用於初始化資源,有時找不到資原始檔時可以嘗試使用此方法。
4、QSplashScreen的使用,用於顯示啟動時的動畫視窗。
5、當在windows中使用Qt進行程式設計時,要處理windwos的中Qt沒有處理的事件,例如usb裝置的接入事件
此時可以重新實現bool QWidget::winEvent(MSG*msg,long*result),也可以重新實現bool QCoreApplication::winEventFilter ( MSG * msg, long * result ),但建議重新實現bool QWidget::winEvent(MSG*msg,long *result)。
如果不對某個窗體控制代碼註冊申請裝置通知,則每次不管裝置接入還是拔出,msg->wParam值均為7(DBT_DEVNODES_CHANGED),達不到我們所要的結果,向系統申請裝置通知的程式碼如下(可以在主視窗的建構函式中使用):
DEV_BROADCAST_VOLUME pDevBroadCastData; pDevBroadCastData.dbcv_size = sizeof(DEV_BROADCAST_VOLUME); pDevBroadCastData.dbcv_devicetype = DBT_DEVTYP_VOLUME; HDEVNOTIFY deviceNotifier = RegisterDeviceNotification(winId(), &pDevBroadCastData, DEVICE_NOTIFY_WINDOW_HANDLE);
注意標頭檔案中必須按如下順序包含
#define _WIN32_WINNT 0x0500
//#define _WIN32_WINDOWS 0x0500
#define WINVER 0x0500
#include <windows.h>
#include <dbt.h>
如果不按照以上順序寫,則可能出現如下錯誤:
error: 'DEVICE_NOTIFY_WINDOW_HANDLE' was not declared in this scope
error: 'RegisterDeviceNotificationW' was not declared in this scope
主要是以上藍色區域文字條件編譯的結果。
/*------------------------------------------------------------------
FirstDriveFromMask (unitmask)
Description
Finds the first valid drive letter from a mask of drive letters.
The mask must be in the format bit 0 = A, bit 1 = B, bit 3 = C,
etc. A valid drive letter is defined when the corresponding bit
is set to 1.
Returns the first drive letter that was found.
--------------------------------------------------------------------*/
char FirstDriveFromMask(quint32 unitmask)
{
char i;
for (i = 0; i < 26; ++i)
{
if (unitmask & 0x1)
break;
unitmask = unitmask >> 1;
}
return (i + 'A');
}
(a)
bool MainWindow::winEvent(MSG* msg, long * result)
{
bool bResult = false;
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 lpdbInterface =
(PDEV_BROADCAST_VOLUME)lpdb;
char diskID = FirstDriveFromMask(
lpdbInterface->dbcv_unitmask);
QString mountedName = QString::fromAscii(&diskID, 1);
mountedName = mountedName + ":\\";
appearedDeivce(mountedName);
}
bResult = true;
break;
case DBT_DEVICEREMOVECOMPLETE:
if(lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbInterface =
(PDEV_BROADCAST_VOLUME)lpdb;
char diskID = FirstDriveFromMask(
lpdbInterface->dbcv_unitmask);
QString mountedName = QString::fromAscii(&diskID, 1);
mountedName = mountedName + ":\\";
disAppearedDevice(mountedName);
}
bResult = true;
break;
default:
bResult = true;
break;
}
}
(b)
最後,如果重新實現bool QCoreApplication::winEventFilter ( MSG * msg, long * result )可能導致一個問題,就是每次裝置的插入和彈出事件將接受兩次,所以,建議重新實現bool QWidget::winEvent(MSG*msg,long*result)。
後來重新測試,其實直接重新實現bool QCoreApplication::winEventFilter ( MSG * msg, long * result )也能實現,且無需向系統申請裝置通知,直接拷貝程式碼(a)、(b)並修改為相應的函式名,但有一點需要注意,在Qt中除錯,斷點不能打在switch語句處,否則每次均只能接收到7(DBT_DEVNODES_CHANGED),直接開啟case內即可進入。
6、關於usb裝置,由於如果開啟軟體之前,裝置已經接入,則無法收到usb裝置的接入事件,導致軟體中無法正確顯示。
GetLogicalDriveStrings()函式來查詢當前所有邏輯驅動器的根驅動器路徑;
GetDriveType()判斷一個磁碟驅動器的型別;
CreateFile()開啟一個裝置控制代碼;
DeviceIoControl()對開啟的裝置控制代碼進行操作;
CloseHandle()關閉裝置控制代碼;
GetDiskFreeSpace()獲取與一個磁碟的組織有關的資訊,以及瞭解剩餘空間的容量;