QT Win32下的消息派送机制

 

QT Win32下的消息派送机制

——QEventDispatcherWin32

昨天为了准备接下来的比赛,做了一个双链表的快速排序,弄到了很晚,又一次没有进行我的源码分析。今天又忙到现在才有一会属于自己的时间去做源码分析。

今天主要的入手点是Qt底层的消息传递机制,主要分析Windows下的实现机制,这样就需要对QEventDispatcherWin32类进行分析了:

class Q_CORE_EXPORT QEventDispatcherWin32 : public QAbstractEventDispatcher

{

    Q_OBJECT

    Q_DECLARE_PRIVATE(QEventDispatcherWin32)

 

    void createInternalHwnd();

    friend class QGuiEventDispatcherWin32;

 

public:

    explicit QEventDispatcherWin32(QObject *parent = 0);

    ~QEventDispatcherWin32();

 

    bool processEvents(QEventLoop::ProcessEventsFlags flags);

    bool hasPendingEvents();

 

    void registerSocketNotifier(QSocketNotifier *notifier);

    void unregisterSocketNotifier(QSocketNotifier *notifier);

 

    void registerTimer(int timerId, int interval, QObject *object);

    bool unregisterTimer(int timerId);

    bool unregisterTimers(QObject *object);

    QList<TimerInfo> registeredTimers(QObject *object) const;

 

    bool registerEventNotifier(QWinEventNotifier *notifier);

    void unregisterEventNotifier(QWinEventNotifier *notifier);

    void activateEventNotifiers();

 

    void wakeUp();

    void interrupt();

    void flush();

 

    void startingUp();

    void closingDown();

 

    bool event(QEvent *e);

 

private:

    friend LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);

};

该类的定义很简单,其中有一些非常熟悉的函数:

bool processEvents(QEventLoop::ProcessEventsFlags flags);

该函数是之前在exec()中看到的那个调用的实现部分。

void registerSocketNotifier(QSocketNotifier *notifier);

void registerTimer(int timerId, int interval, QObject *object);

bool registerEventNotifier(QWinEventNotifier *notifier);

接下来的三个函数应该分别是对网络事件、定时器事以及其他事件的通知信号注册。

我想,最熟悉的莫过于:

friend LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);

这个函数代表了已经是Win32API函数,这样针对底层的应用了。可见,Qt也是从该函数得到一些通知消息的。我们接下来看下该类这些函数的实现。先看下最熟悉的那个回调函数:

LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)

{

    if (message == WM_NCCREATE) {

            return true;

    } else if (message == WM_USER) {

 

        // socket notifier message

        MSG msg;

        msg.hwnd = hwnd;

        msg.message = message;

        msg.wParam = wp;

        msg.lParam = lp;

 

        QCoreApplication *app = QCoreApplication::instance();

        long result;

        if (app && app->filterEvent(&msg, &result))

            return result;

 

        int type = -1;

        switch (WSAGETSELECTEVENT(lp)) {

        case FD_READ:

        case FD_CLOSE:

        case FD_ACCEPT:

            type = 0;

            break;

        case FD_WRITE:

        case FD_CONNECT:

            type = 1;

            break;

        case FD_OOB:

            type = 2;

            break;

        }

        if (type >= 0) {

 

    #ifdef GWLP_USERDATA

            QEventDispatcherWin32 *eventDispatcher =

                (QEventDispatcherWin32 *) GetWindowLongPtr(hwnd, GWLP_USERDATA);

    #else

            QEventDispatcherWin32 *eventDispatcher =

                (QEventDispatcherWin32 *) GetWindowLong(hwnd, GWL_USERDATA);

    #endif

            if (eventDispatcher) {

                QEventDispatcherWin32Private *d = eventDispatcher->d_func();

                QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };

                QSNDict *dict = sn_vec[type];

 

                QSockNot *sn = dict ? dict->value(wp) : 0;

                if (sn) {

                    QEvent event(QEvent::SockAct);

                    QCoreApplication::sendEvent(sn->obj, &event);

                }

            }

        }

        return 0;

 

    } else if (message == WM_TIMER) {

 

        MSG msg;

        msg.hwnd = hwnd;

        msg.message = message;

        msg.wParam = wp;

        msg.lParam = lp;

 

        QCoreApplication *app = QCoreApplication::instance();

        Q_ASSERT_X(app, "qt_interal_proc", "Timer fired, but no QCoreApplication");

        if (!app) {

            KillTimer(hwnd, wp);

            return 0;

        }

 

        long result;

        if (app->filterEvent(&msg, &result))

            return result;

 

        QEventDispatcherWin32 *eventDispatcher =

            qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());

        Q_ASSERT(eventDispatcher != 0);

        QEventDispatcherWin32Private *d = eventDispatcher->d_func();

        d->sendTimerEvent(wp);

        return 0;

    }

 

    return  DefWindowProc(hwnd, message, wp, lp);

}

这里主要通过该部分将消息传递到Qt应用程序中:

QCoreApplication *app = QCoreApplication::instance();

        long result;

        if (app && app->filterEvent(&msg, &result))

            return result;

值得关注的是GetWindowLongPtr函数和SetWindowLongPtr,在以前的程序编写过程中,没有用过。查了下,原来是用来保存一些指针的,通过SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher);方法进行设置,再调用GetWindowLongPtr(hwnd, GWLP_USERDATA);进行读取,最后需要转换为自己需要的指针类型即可。

当得到的是定时器消息时,通过d->sendTimerEvent(wp);方法将消息发送,最终调用timerEvent方法。

最终是非常熟悉的DefWindowProc(hwnd, message, wp, lp);方法。

在看完这个回调函数之后,顺便看到了创建窗口的函数:

static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher)

该函数没有什么特别的地方。

另外一个定义的静态方法是:

void WINAPI CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/, DWORD_PTR user, DWORD_PTR /*reserved*/, DWORD_PTR /*reserved*/)

{

    if (!timerId) // sanity check

        return;

    WinTimerInfo *t = (WinTimerInfo*)user;

    Q_ASSERT(t);

    QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId));

}

可以看到,该方法是用来对定时器消息进行发送的。

我们再看下createInternalHwnd()方法,该方法调用了qt_create_internal_window方法,这样,创建了最底层的Win32应用程序。

接下来看到了事件循环需要调用的一些函数:

// ### Qt 5: remove

Q_CORE_EXPORT bool winPeekMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin,

                     UINT wMsgFilterMax, UINT wRemoveMsg)

{

    return PeekMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);

}

 

// ### Qt 5: remove

Q_CORE_EXPORT bool winPostMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

    return PostMessage(hWnd, msg, wParam, lParam);

}

 

// ### Qt 5: remove

Q_CORE_EXPORT bool winGetMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin,

                     UINT wMsgFilterMax)

{

    return GetMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax);

}

但是好像Qt要在5.0版本以后采用新的机制进行。

这里其他的函数没有什么太多的意义了,接下来就是看下事件是怎么循环起来的,或许QEventLoop中会有些我们想要的东西。不过今天的时间已经不允许了,只能明天再来分析。

20091029日星期四 2353

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值