您的位置:首页 > 编程语言 > Qt开发

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

2016-12-07 19:54 330 查看


为什么

为了显示微信登录的二维码,引入了整套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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息