实例1我们做了一个查找框,这东西必须得配合文本才能发挥作用,所以我们再做一个很简单的文本编辑器。
Qt里面有一个叫做QPlainTextEdit的东西可以实现文本编辑的功能,类似于HTML里的textarea。废话不多说,我们开始写代码。
我们用QPlainTextEdit实现文本编辑功能
1.新建一个项目,名字就叫editor吧,取消创建界面,类名默认,基类默认为MainWindow就可以了。
2.修改mainwindow.h,给他一些类和变量的声明:
#define MAINWINDOW_H
#include <QtGui/QMainWindow>
class QPlainTextEdit;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QPlainTextEdit *textArea;
};
#endif // MAINWINDOW_H
修改mainwindow.cpp,把声明的组件加进去:
#include <QPlainTextEdit>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle(tr("MyEditor"));
//类似于html里的textarea
textArea = new QPlainTextEdit;
//设为中央部件
setCentralWidget(textArea);
}
MainWindow::~MainWindow()
{
}
点击绿色播放按钮运行一下看看效果吧,我们可以在里面写文字了:
ActiveX简介
ActiveX作为一种古老的技术曾经辉煌一时,因其安全性一直被人们所诟病,现在很多功能已被其它技术
(Silverlight、Flash、html5)所取代。为什么ActiveX不安全呢?因为安装后它可以操作本地电脑资源,
这就人们又爱又怕的地方,爱的是开发人员,利用它可以做很多事,很多事Web或其它技术不能做的事情,
比如:自动读电脑的目录并上传资料,修改电脑的一些设置等。使用者怕它会不会在自己的电脑里面做一
些坏事,比如:窃取用户电脑资料、种植木马等等。
虽然ActiveX渐渐的在退出历史的舞台,IE对它的限制也越来越严格,但是现下还有很多地方在使用这一项技术。
比如网上银行和一些登录安全安求比较高的网站密码框(如:淘宝)用的就是它了,文件上传,网站需验证用户
电脑IP,MAC地址,网上视频,监控等等。
截屏并上传插件开发
开发原因
从事MIS系统开发多年,在维护系统的时候,经常有一些新来的同事在使用系统时,出现一些问题。
于是老打电话给IT的系统护人员资询,说系统出错了。系统护人员就问出现什么错误,用户有时又描述不清,
于是要求用户截个屏看看是什么情况,或者干脆走到用户里去。有时候新人连截屏都不知道,还有怎么发给你
看等一系列问题,IT系统护人员你是不是也经常遇到这样的问题,是不是被这样的事烦透了呀。所以一直想开
发一个能自动截屏并上传的功能,Web不能操作客户端所以没法截屏,只能用其它技术,于是便有了开一个
ActiveX控件截屏并上传到指定页面的想法。
技术选择
自己大学入门的第一门语言便是C语,印象非常深刻,也学了一期VC好像没学到什么东西,之后就老师引入了
VB.NET这门课,VS2002新建窗体拖控件,太强太神奇了,后来出来工作公司用的是VS2003用的是C#,自己
也自然而然改投C#门下,一直至今。开发ActiveX控件有很多个方法,可以用VB、Delphi、C、C++等等,
C#也能开发前提是使用ActiveX控件的客户端得装一个.NET框架,这点让人受不了。于是决定采用C++开发。
学习历程
寻觅ATL开发教程。《Visual.C.6.0Active.XNathan.Wallance.pdf》这本教材作为入库级的教材相当不错,
《ATL开发指南.pdf》这本稍深入一点。 了解一下COM,确实是一个复杂的技术,不是专业人士是很难开发的,
我只是开一个截屏上传的功能,所以其它不相关的只是了解,也没精力深入学习冲冲越过。
用C++开发ActiveX可采用MFC\ATL两种方式。MFC类库全开发方便快捷,但是控件体积相对来讲要大一点,
而ATL正是为开发ActiveX而生,控件体积小,类库当然没有MFC的全了,所以很多东西得自己实现,VC5.0\6.0
之后引用了向导开发工作简化了很多,新手也更容易入门,开发一些简单的控件应该也不再是一件很困难的事情了。
也看了很多人写的博客教程,开始平台用的是VC6.0因为与本机总是不兼容而告吹,其实VS20XX中的Visual C++
也是可以开发的。
功能分析
1)截取客户端屏幕,这个不需要用户截取指定区域,直接抓取用户的整个屏幕即可,
所以控件不需要界面。
2)上传到指定的网页,所以得有网络传输的功能。
技术实现
原则:尽量用最底层的类库,最好是系统自带的这样控件体积就越小安装越方便,无需引入其它dll或框架之类的。
一、屏幕截取
1)获取屏幕,可以通个窗口句柄,获取屏幕,也可以CreateDC创建 HDC对象等。
2)保存操作,遇到了一个艰难的选择,一是自写实现保存为位图,如果想保存其它格式(jpg)那得写一堆代码。
二是引入高级一点的类库,atlimage.h头文件里面有CImage这个类,一个Save指定一下格式就可以搞定。
二、图片上传
1)网络通讯功能最底层当然是socket了,http post 上传文件,这个得先熟悉一下http的协议,因为一直从事WEB开发,
对个已经相当熟知了,于是用Firefox浏览器中用HttpFox抓取了上传的POST文本,按照这个拼装。socket怎么使用,
网上搜索一番,整理一下,然后按照这个开始发数据到测试上传网页,一直不成功。拼装的字符串看了一遍又一遍,
与协议反复核对,换行是否正确分隔线是否正确,其实在这里我范一个错,我把头部boundary的分隔线直接复制到后面
文件分隔用了,结束后要多加--这个当然知道了,于是上网搜一个http抓包的工具 sniffer专业版,安装调式程序居然没抓
到包,专业版太专业了不好用,也可以是自己没用习惯吧,又换一款Fiddler抓包工具,测试了一几个网址,Fiddler果然
不错简洁不少。令人失望的是也没抓到包,开始怀念以前sniffer的一个简易版了,不管是什么数据,只要是有通讯都能抓。
终于到了一款MiniSniffer虽然跟以前的那一款不同,但同样可以抓通讯数据, 这下终于能监控到发送的数据了,核对发送
的数据也没错呀,悲摧了。经过几天的拆腾,放弃用socket了,继续搜寻看看C++下http通讯的有那些类,MFC下有
CInternetSession等系列类,C++稍高层的有HINTERNET系列,ATL7.0以上提供了CAtlHttpClient类,经过筛选比
较之后锁定用HINTERNET来开发,网上看例子看API学习,真的是被C++的类型打败了,又花了一点时学习这些类型及
关系,不得不感叹c++的复杂与强大,原来C#的泛型在C++下早就有了,我相信应该还有很多功能其很早就有了,只是
现在变得很加好用了,同为VS IDE下的产品与C#的编程环境就差别那么大呢? Visual C++没有提示,不会智能补全,
删除大括不对齐,太多不方便了。又到了激动人心的时该了,调试又是不成功,这次又启用Fiddler可以监控到,也看到了
发送的数据,核对核对。折腾了几天,到网上搜了几个例子,原原本本的的复制下来,其它也没有几个可行的,几经努力找
到一个可行了,写法都差不多呀,后来无意中,我把头部的boundary的分线复制下与文件的分线进行对比发现了一个,令人
兴奋的差异就是文件、控件表单名分隔多了两个--,修改后哇成功了。回头把socket做的方案修改了一下也成功了。最后就是
接收返回的信息,需要把char字符转换成UTF-8就行了,socket收接信息包含了http信息,需要把头截取返回信息体即可,
c/c++毕竟不是很熟识,操作也没高级语言方便所最的采用了HINTERNET的实现,图片保存也用CImage这个类,
最终功能完成。
小结:自已对http协议看得不是太仔细,一个细小的错误,导致花费具多的时间,不过也学到了很多东西。
还有就是越高级的类越好用。
功能测试
1、正常测试
网页一加载调用,截屏上传OK一切正常。
2、压力测试
去掉提示按住F5不放(其实可在js里面写个循环的),一张张截屏不断的出现在upload文件夹里面,不错,
打开Windows任务管理器,CPU时高时低正常,内存不断在增加,关闭IE内存恢正常,不这个太满意。
3、异常测试
1)传入错的url,返回找不资源正常返回,再刷新出错IE崩了。
2)网络断开,报错正常返回异常,再刷新出错IE崩了。
3)网站停掉,报错正常返回异常,再刷新出错IE崩了。
小结:内存增加关键资源未释放、或对c/c++的char/char[]/指针等的错误使用,IE崩溃发现在异常抛出,提示堆栈异常,
有个BSTR*的返回类型,对BSTR类型赋值错误操作所致。错误用法 *pVal=L"有异常";正确用法使用:
:SysAllocString赋值。前前后后修改与优化再测试用了几天最后一切正常了。
系统发布
ActiveX有这么几种后缀dll、exe、ocx等,为了便于用户安装或网络传输,一般需要打包成cab压缩包,最后就是签名
这个系列是本人在工作或工作之余开发和学习C\C++的一些笔记。本文涉及C++/CLI的一些内容。
本文为原创,首发于我的个人博客:.NET程序员的C\C++情结(3)。欢迎交流指正。转载请注明出处。
虽然现在主要从事.NET平台的开发,但是一直以来对C\C++有着那份难以割舍的情结。本文会涉及到托管C++的一些随笔记录。
当然,如果写纯.NET应用的话,C#无疑是最合适的语言的。但是托管C++在同时处理Native调用和托管调用上无疑是十分吸引人的,往往用来作为托管世界和Native世界的桥梁。当然。你可以说用.NET的“平台调用”特性同样能够胜任,萝卜青菜各有所爱吧。
托管C++基础语言特性
在托管C++中需要像下面这样定义一个托管类型
{
public:
property UInt32 FieldId;
}
默认情况下这样的类是默认实现IDisposable的,原因很简单,既然用到C++来封装托管类型,那么八成类型需要涉及到非托管对象,实现IDisposable减少了出错的可能。可以同时实现两种“析构函数”:
~ARSession(void)
前者是好比Dispose(),后者是C++原生的析构函数。
可以同时引用托管的命名空间和C++命名空间
using namespace System::Collections::Generic;
using namespace std;
也可以向普通C++一样#include头文件,编译的过程可以理解成跟本地C++的编译过程一样,只是在编译的时候会有/clr开关,并至少引用相应的托管dll:mscorlib.dll
对于托管类型,在类型的标识右使用”^”标注,比如:
array<String^>^
List<AREntry^>^
但注意,对于Nullable的值类型,使用
而不是
前者在C#中会看到是uint?,而后者在C#中会看到是ValueType
托管C++支持类似C#中的ref
out的话需要加一个Attribute
void foo([Out] Bar^% x);
在本地堆中申请内存是使用new关键字,而在托管堆中申请内存,使用gcnew关键字:
托管C++的内存管理
上面简单介绍的一些语言特性是我实际碰到的,可能不全。与语言特性相比,更为重要的是内存管理带来的复杂性。原生的C++只有一个由C运行库管理的“本地堆”,而C++/CLI允许同时操作本地堆和托管堆。众所周知,托管堆由CLR管理,在托管堆中的内存会随时被CLR回收和压缩,这意味着,如果使用C#的引用或者C++/CLI中的“Handle”(即由String^等“戴帽子的类型“声明的变量)来操作托管堆的内存,不会有任何问题,因为CLR会自动更改引用或Handle指向的地址。然而,如果在本地堆或者栈上的本地指针来指向托管堆上的内存的话,CLR不会对压缩内存带来的地址修改负任何责任。如果发生这种情况的话,再次使用该指针将导致内存违规。下面这张图可以解释这个现象(图片来源http://www.codeproject.com/Articles/17817/C-CLI-in-Action-Using-interior-and-pinning-pointer):
在上图中,本地指针指向的地址本来是Data,但是当CLR的GC工作后,Data可能被压缩至托管堆的其他地方,而取而代之的是另外一块内存。很典型的情况就是,我们要在托管的byte[]和非托管的usigned char*对象之间传递内存,下面这段代码将String对象转化成以UTF8编码的字节数组:
{
if(String::IsNullOrEmpty(Source))
return NULL;