QT通过QAxWidget嵌入IE浏览器并获取页面源码

5 篇文章 0 订阅

为什么


为了显示微信登录的二维码,引入了整套QtWebEngine,占用非常大的空间。微信登录二维码有自动刷新动作,这些定义在页面脚本中,所以不能直接自绘二维码方式实现,浏览器少不了。

主要原理


通过COM组件可以调用系统自带的浏览器,当然是IE啦。Qt提供QAxObject和QAxWidget对象帮助访问COM,(与其说帮助,还不如说越帮越忙)

怎么做


请注意接下来描述的每一步,在完全理解前,不要擅自调整

1. 创建或者基于已有的Qt设计师界面类,就是有.ui文件的那种。但是奇葩来了,完整的设置通过“设计”是搞不出来的。所以随便拉个QAxWidget吧。

2. 通过用文本编辑器的方式打开对应的ui文件


3. 找到<customwidgets>,往里面插入一组提升设置


4. 把界面上的QAxWidget找到,改成如下样式,objectName会在每次用"设计"改ui的时候被覆盖掉(悲剧),control里面的guid是对应IWebBrowser2接口的,固定就那么写。


5. 照着模样做一个WebAxWidget.h。注意,集成QAxWidget的类不能声明Q_OBJECT,会导致activeqt机制里面moc无效,表现看这里stackoverflow

#ifndef WEBAXWIDGET_H
#define WEBAXWIDGET_H
#include <ActiveQt/QAxWidget>
#include "windows.h"

class WebAxWidget : public QAxWidget
{
public:

    WebAxWidget(QWidget* parent = 0, Qt::WindowFlags f = 0)
        : QAxWidget(parent, f)
    {
    }
protected:
    bool translateKeyEvent(int message, int keycode) const Q_DECL_OVERRIDE
    {
        if (message >= WM_KEYFIRST && message <= WM_KEYLAST)
            return true;
        else
            return QAxWidget::translateKeyEvent(message, keycode);
    }
};
#endif // WEBAXWIDGET_H

6. 在你的ui文件对应的界面类里面,声明槽,注意命名形如 on_WebBrowser_ProgressChange. 其中WebBrowser为前面objectName所写,ProgressChange是回调函数的名字,它的出处是MSDN里面IWebBrowser的声明(好吧,我也是蒙的,在第5中所说的错误状态下,可以即时看到QObject::receivers: No such signal mis::WebAxBrowser::DownloadComplete()这样的提示,就是说你的命名对了,槽就会被调用,而不需要手动去连接).稳妥的办法是去qt sample:webbrowser里面抄几个.


7. 让槽函数转调一个专门处理它的类,我创建了一个WebAxWrapper,把回调处理后转成类似QWebEngineView的信号:loadFinished和loadProgress


8.当然还有load()和url()


9. 最后值得一提的是拿页面源码。找了很多帖子,期间想到Javascript法,结果IHTMLWindow2里面的execScript方法不能拿到返回值,网上文章一大堆,还有反汇编C# InvokeScript()方法的.最后找到了流化方案。我做了一个像QWebEnginePage的toPlainText方法

void WebAxWrapper::toPlainText(void (*f)(const QString &))
{
    char *output = NULL;
    QAxObject *document = WebBrowser->querySubObject("Document");
    if(document)
    {
        IHTMLDocument2 *doc2 = nullptr;
        document->queryInterface(QUuid(IID_IHTMLDocument2), (void**)&doc2);
        if (doc2)
        {
            IPersistStreamInit *pPSI=NULL;
            IStream *pStream=NULL;
            HGLOBAL hHTMLText;
            if (SUCCEEDED(doc2->QueryInterface(&pPSI)))
            {
                const int MaxBuffSize =64*1024;
                hHTMLText = GlobalAlloc(GMEM_FIXED, MaxBuffSize);
                CreateStreamOnHGlobal(hHTMLText, TRUE, &pStream);
                pPSI->Save(pStream, FALSE);
                LARGE_INTEGER li;
                li.QuadPart = 0;
                pStream->Seek(li,0,NULL);
                output = new char[MaxBuffSize];
                output[MaxBuffSize-1] = 0;
                ULONG readed = 0;
                pStream->Read((void*)output,MaxBuffSize-1,&readed);
                output[readed] = 0;
                pStream->Release();
                //GlobalFree(hHTMLText);
                pPSI->Release();
            }
            doc2->Release();
        }
    }

    if(output)
    {
        qDebug()<<output;
        f(QString::fromUtf8(output));
        delete[] output;
    }
    else
    {
        f(QString());
    }

}

需要windows的头文件

#include <ExDisp.h>
#include <shlguid.h>
#include <MsHTML.h>
#include <QUuid>

10. 二维码,其实最后这个不是重点了,直接把我们的页面(http://passport.timelink.cn/wechat/show)显示出来,当发生loadFinished的时候,获取一下当前url,如果不同了,分析一下页面源码,我们的项目在这一步服务器返回一段json,解析并处理就可以了。


最后

 


ie浏览器右键菜单真是又多又杂...


欢迎访问我们的轻录课项目,以及分课网 http://fenke.timelink.cn


  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值