1. 程式人生 > >qt main 函式的幾個實用性的做法(包括單啟動、檢測usb接入事件)

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()獲取與一個磁碟的組織有關的資訊,以及瞭解剩餘空間的容量;