漂亮的界面实在有点诱人(相当诱人,特别是WIN7出来之后)。如果所有人都WIN7,就天下太平了,直接搞C#就行,头上有WIN7顶着,还能难看到哪里去,可是WIN XP等老货才是大众的,特别是办公室里的上班族,WIN7不是随随便能换上去的,要知道巨多的办公室电脑连光驱都没。于是我从VFP转向VC。当然DirectUI和WPF更牛,可是咱小本买卖,玩不起。其实也不想咋地,就想贴贴图什么的,把标题栏给去掉,然后自个儿鼓捣。
数来数去,终于决定用webbrowser搞,不是太难,也有HTML基础。不过事情越来越大条。 其实呢没什么大不了的,我想做的应用程序么,不就是存取、检查数据,然后输出报表什么的。我就这点需求。VFP完全都搞的定,但CD(注意是大写)的WIN7来了,我慌了,脸面还是很重要的(废话:咱爷们会无视美女吗!)。关键是,我想自已做个网站,然后在上面发布我的作品,如果还不讲究一点,可能会赔本的。小本买卖么,亏了就没了。
最开始想直接在VFP上做,可是WEBUI做的再美,头上顶个蓝条子加白字————“不兼容”。想想来想去,觉得还是试试VB吧,它能比较方便的运用绘图的API。于是我贴图上,双缓冲上,子类化上。外表终于写好了,用表单模拟了菜单(可以随便画),表单的吹拉弹唱全都通过子类化搞掂了,我以为我成功了,于是兴冲冲的上HTML。数据格式也全都转换为XML,我所做的程序不太会针对大量的数据记录,只是参数比较多,而且更新频繁,XML完全能胜任(PS:以前一直觉得用VFP处理这种小型的数据完全是浪费,可咱只会VFP)。可是做了一半发现不对劲,HTML和JS完全暴露了,如果将程发布了,一切都是透明的。咱不高尚,公开源码这种事坚决不干,于是想了一个办法,表单打开的时候加载一个起始页,加载完毕后,比较重要html段通过调用innerHTML来替换,JS么,加个defer属性也能行,为了安全起见,替换之前可以通过操作DOM将所有JS和BODY内的HTML代码都掐掉。我相当高兴,于是想办法加密那些所谓的HTML段————(大写)CD,悲剧又开始了。
加密么,原来是没什么概念的,但要加密那些关键的HTML,只好再想办法,其实也不用想什么办法,BAIDU+GOOGLE:VB怎么加密字符串?VB我也初学而已,网上有些提点,但搞不明白,但无意看到了microsoft上有一个示例,就是将空字符缓冲区的引用传递给C++写的DLL,然后由C++来填充VB传递过去的字符串缓冲。看了很久终于弄清楚了流程,可是C++不会,VC也不会,那会儿连MFC和VC有什么不一样都不知道。我忍,我学。我知道,我并不要做很复杂的事情,只想对字符串搞点异或(?有人会么)什么的。
于是暂时放下了HTML的编辑,去了趟书城,弄了堆C++,VC的书,还搞了本汇编的(不知道为什么会搞一本)。咱天天要上班,原来的学文科的,没什么基础,也没什么懂计算机的朋友,VFP、VB全靠自学。由于所做的事情一直都很简单,就是前面说的————存取、检查数据、输出报表,所以VFP前后搞了两年,VB么,因为只要贴图,学这点本事也就半年(PS:别的地方可以捅戳,这里别拍砖,实在是痛过了不想再痛)。
嗯,从去年秋天开始学C++,先看了看书,抄了个MD5的C++示例,哈,跑起来了,和VB版本的MD5字符串加密得到了一样的结果。看书,抄代码、改代码,慢慢觉得,这活是人干的么?CD,怎么VB版的MD5和C++版的MD5对同一文件产生的密码不一样,但字符串却一样呢?于是,网络,书城就成了业余的全部。终于在今年初的时候,决定转向VC++,因为我做的事情有很多人做过了,而且找到了几个MFC的源码,相对来说,VC++的源码比VB、VFP好找些。VC6.0的IDE能用的上了,MSDN也有点看的懂了。
-----------------------------------------------------------------
-----------------------------------------------------------------
终于在一个半月之前,我开始了MFC+Webbrower的工作旅程,最后定下了这种框架:
1、工程是基于对话框的,就是mfcdriller示例那样做的,但不同的是,用了一个对话框的派生类作为程序中所有的对话框的基类,在该基类中写上所有子类需要实现的虚方法,功能实现则在子类中重写方法(不需要就不写,自已在网页中external,不会调度错的),非界面相关的方法调用通过HTML发出external指向IDispatch来工作。IDispatch的Invoke:
HWND hWnd=GetActiveWindow();
CCustomForm* pDlg = (CCustomForm*)CWnd::FromHandle(hWnd);
pDlg->/*调用所需的方法*/;
2、基类的一个成员是对话框类型,但是无边框,用以模拟菜单;还有几个公共成员用来记录模拟菜单的动作。点击模拟菜单时,将点击位置传递给那些主对话框的记录模拟菜单动作的成员,然后,隐藏菜单,调用基类或子类的菜单处理方法,就像IDispath一样的工作方式。
3、对话框无边框,外观是自绘的,用GDI+和双缓冲实现,将一切都实现在客户区,唯一需要的就是分析菜单、标题栏、工具栏的工作方式,然后模拟。全真无控件模似(像不像DirectUI?高兴:拒绝拍砖),对话框就要时刻记录鼠标位置就行,吹拉弹唱在OnNcHitTest替换相关消息就可以,唯一麻烦的是无边框窗口最大化时有点麻烦,不过我还是解决了.电脑么,学名是计算机,精髓就是计算,精密计算才是王道。
4、HTML加载则是通过IPersistStreamInit接口来实现,因此加载前可以对加密了的HTML代码段进行解密处理(哭:改造了一个示例的时候有一句
LPTSTR lpMem = (LPTSTR)::GlobalAlloc( GPTR,::strlen(lpHtml)+1 )
我一不小心写成了
LPTSTR lpMem = (LPTSTR)::GlobalAlloc( GPTR,::strlen(lpHtml+1) ),
F5 9 10了一晚上都没找出来,IDE还是用的不熟)。
框架经过简单的测试,貌似没什么问题,唯一不顺眼的是,如果点击模拟菜单后new了一个新的对话框,模拟菜单ShowWindow(SW_HIDE)后,会在webbrowser上留一点残影,然后才弹出新的对话框,实在不知WHY。我的菜单是这么 工作的:点击菜单(非模态对话框模拟的)->隐藏菜单->调用主对话框的方法->在主对话框的方法中关闭菜单->主对话框打开一个新模态对话框。实在不明白为什么会有残影,如果菜单关闭后不是执行打开新窗口这种操作,就不会有残影。
我不知道,如果基类的虚方法数量太多是否严重影响性能,比如超过300个。IDispatch中是用Switch(dispIdMember)来工作,如果Switch分支太多是否严重影响性能,比如超过300个(我原来VFP程序里就有这么多事情要做)。
//抄的
STDMETHODIMP CImpIDispatch::GetIDsOfNames(
/* [in] */ REFIID riid,
/* [size_is][in] */ OLECHAR** rgszNames,
/* [in] */ UINT cNames,
/* [in] */ LCID lcid,
/* [size_is][out] */ DISPID* rgDispId)
{
HRESULT hr;
UINT i;
// Assume some degree of success
hr = NOERROR;
for ( i=0; i < cNames; i++) {
CString cszName = rgszNames[i];
if(cszName == cszBP_IsOurCustomBrowser)
{
rgDispId[i] = DISPID_BP_IsOurCustomBrowser;
}
else if(cszName == cszBP_Close)
{
rgDispId[i] = DISPID_BP_Close;
}
......
else if (cszName == cszBP_DoSomething)
{
rgDispId[i] = DISPID_BP_DoSomething;
}
else if (cszName == cszCU_ShowMenu)
{
rgDispId[i] = DISPID_CU_SHOWMENU;
}
else if (cszName == cszCU_ContextMenu)
{
rgDispId[i] = DISPID_CU_CONTEXTMENU;
}
else
{
// One or more are unknown so set the return code accordingly
hr = ResultFromScode(DISP_E_UNKNOWNNAME);
rgDispId[i] = DISPID_UNKNOWN;
}
}
return hr;
}//抄的
这个For循环的cNames是依据什么而来的?如果cNames太多会不会严重影响程序性能有。
希望有做过这方面的大侠、大大提点点,被VB搞怕了,如果大侠们都认为我么个框架有重大缺陷,我练练再来。
其实我这个框架,如果只用一个对话框也能做,只要new就行。但这样的话,每个new出来的对话框都有一个庞大的结构,完全浪费,所以还是通过派生继承来搞。只是基类总归要写上所有子类方法的的虚方法(能这么说么?),算不算是掩耳盗铃之举。