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中会有些我们想要的东西。不过今天的时间已经不允许了,只能明天再来分析。
2009年10月29日星期四 23:53