现在的位置: 首页 > 综合 > 正文

QtCoreApplication(续二)

2013年10月27日 ⁄ 综合 ⁄ 共 4435字 ⁄ 字号 评论关闭

QtCoreApplication(续二)

经过两天时间的奋斗,一个php的简单网站终于做完了,可以重新回到这里,专心分析我的Qt源代码了,感觉很好。

今天主要的研究对象就是在Windows系统环境下的事件派送器(QEventDispatcherWin32),该类继承自QAbstractEventDispatcher,提供在Windows平台下的事件机制封装。

#elif defined(Q_OS_WIN)

    eventDispatcher = new QEventDispatcherWin32(q);

这里通过new的方式创建了对象,其构造函数实现如下:

QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)

    : QAbstractEventDispatcher(*new QEventDispatcherWin32Private, parent)

{

}

创建了QEventDispatcherWin32Private的引用,该类构造函数如下:

QEventDispatcherWin32Private::QEventDispatcherWin32Private()

    : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0)

{

    resolveTimerAPI();

 

    wakeUpNotifier.setHandle(CreateEvent(0, FALSE, FALSE, 0));

    if (!wakeUpNotifier.handle())

        qWarning("QEventDispatcher: Creating QEventDispatcherWin32Private wakeup event failed");

}

第一行的:threadId(GetCurrentThreadId()),调用了Windows系统的API函数,获取当前线程的ID,接下来是:resolveTimerAPI()根据函数名猜测是解析时间API函数,进入该函数看一下:

static void resolveTimerAPI()

{

    static bool triedResolve = false;

    if (!triedResolve) {

#ifndef QT_NO_THREAD

        QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));

        if (triedResolve)

            return;

#endif

        triedResolve = true;

#if !defined(Q_OS_WINCE)

        qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("winmm"), "timeSetEvent");

        qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("winmm"), "timeKillEvent");

#else

        qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeSetEvent");

        qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeKillEvent");

#endif

    }

}首先,该函数用局部的静态变量防止了该类被重复调用,接下来的部分,分为了多线程支持和非多线程支持情况下的不同实现方式。在多线程方式下,QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));

通过互斥锁的形式,对互斥池的全局对象进行加锁,在获取全局实例的时候,我进行了跟踪,发现&triedResolve 的作用在这里:

int index = int((quintptr(address) >> (sizeof(address) >> 1)) % mutexes.count());

这样做的有什么用,不是很清楚,在这里,我猜测是通过这样的方式产生一个随机的访问索引位置,之后将该位置的互斥对象返回,如果该位置没有,则创建一个这样的对象。

接下来的ptimeSetEventqtimeKillEvent是两个WindowsAPI函数的函数指针,对QLibrary:: resolve()函数返回的指针进行转换。

QLibrary跟踪之后,找到了,该类的主要实现部分:

bool QLibraryPrivate::load_sys()

该函数首先对文件名进行了处理:

QString path = fi.path();

    QString name = fi.fileName();

    if (path == QLatin1String(".") && !fileName.startsWith(path))

        path.clear();

    else

        path += QLatin1Char('/');

接下来有两行注释:

// The first filename we want to attempt to load is the filename as the callee specified.

    // Thus, the first attempt we do must be with an empty prefix and empty suffix.
      
之后是在Windows下的实现代码

if (!fullVersion.isEmpty()) {

            suffixes << QString::fromLatin1(".so.%1").arg(fullVersion);

        } else {

            suffixes << QLatin1String(".so");

        }

看样子应该是生成了需要加载的库文件,根据版本号的不同,加载的文件后缀不同。

#if defined(Q_OS_AIX)     // Not sure if any other platform actually support this thing.

    if (loadHints & QLibrary::LoadArchiveMemberHint) {

        dlFlags |= RTLD_MEMBER;

    }

#endif

看了上面的注释应该能看出来,原来Qt也有很多需要完善的地方哦,只是之前对它了解的太少了。

接下来的这段代码生成了需要加载的库文件名称,并尝试查看该库文件是否存在。

bool retry = true;

    for(int prefix = 0; retry && !pHnd && prefix < prefixes.size(); prefix++) {

        for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) {

            if (!prefixes.at(prefix).isEmpty() && name.startsWith(prefixes.at(prefix)))

                continue;

            if (!suffixes.at(suffix).isEmpty() && name.endsWith(suffixes.at(suffix)))

                continue;

            if (loadHints & QLibrary::LoadArchiveMemberHint) {

                attempt = name;

                int lparen = attempt.indexOf(QLatin1Char('('));

                if (lparen == -1)

                    lparen = attempt.count();

                attempt = path + prefixes.at(prefix) + attempt.insert(lparen, suffixes.at(suffix));

            } else {

                attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix);

            }

#if defined(QT_HPUX_LD)

            pHnd = (void*)shl_load(QFile::encodeName(attempt), dlFlags, 0);

#else

            pHnd = dlopen(QFile::encodeName(attempt), dlFlags);

#endif

 

#if defined(Q_OS_SYMBIAN)

            // Never try again in symbian, dlopen already handles the library search logic,

            // and there is only one possible suffix.

            retry = false;

#else

            if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) {

                // We only want to continue if dlopen failed due to that the shared library did not exist.

                // However, we are only able to apply this check for absolute filenames (since they are

                // not influenced by the content of LD_LIBRARY_PATH, /etc/ld.so.cache, DT_RPATH etc...)

                // This is all because dlerror is flawed and cannot tell us the reason why it failed.

                retry = false;

            }

#endif

        }

抱歉!评论已关闭.