您的位置:首页 > 其它

VS2008下MFC框架下开发ActiveX项目所遇到问题汇总

2014-02-07 11:53 711 查看
今年找了份工作,主要业务是做银行项目。刚进去正赶上在福州的一个项目。项目的背景是对以前1.1的OCX控件进行重构,包括业务和界面,其中界面是比较大的改动,界面采用DockManger模式,每个控件需要停靠,每个子控件放在单独DLL中,并且是动态加载。

其中控件的界面DockManger框架是重点。一开始接手了这个任务。我的思路是因为在VS2008有MFC框架提供这样停靠功能,但是不知道是否能适合OCX控件,因为停靠的框架窗口是CFrameWndEx,在应用程序中都是以主窗口形式呈现的,但是如果弄到OCX中就必然是以子窗口形式创建COleControl上。知道这肯定会带来隐藏的问题,但是这是个硬要求,那么只能是走一步解决一个了,从后来情况看,确实因为这个原因产生了不少问题。

一开始把CFrameWandEx以WS_CHILD样式创建在COleControl上报错,之后采用的办法是OCX以单文档形式创建,视图用CFormView,然后CFrameWndEx创建CFormView上,如下图:



CFrameWndEx的子视图是放固定的组件,其它可停靠的组件都继承CDockablePane,不停靠的组件创建CFrameWndEx的ChildView里。

这样整个停靠框架就搭建好了。但是在后续过程遇到了一些问题

问题1、拖动组件的时候遇到不适当参数

这个问题是因为MFC框架在停靠时候会自动创建一个

CDummyDockablePane,但是在Create方法中,传入的pParentWnd参数为NULL了。这是因为AFXGetTopLevelFrame函数的缘故,因为CFrameWndEx是以子窗口形式,所以AFXGetTopLevelFrame函数找不到CFrameWnd窗口了。

解决办法尝试过如下:

第一种是自己设置顶级框架窗口(m_pTopFrame全局变量),但是这一种编译不通过,如果要编译通过只能设置项目为静态库。这不符合项目的环境。第二种是捕获异常,这个异常不会导致IE崩溃,只是弹出提示框,所以想到了捕获异常。跟踪MFC框架代码发现可在CMultiPaneFrameWnd的OnMouseMove方法进行捕获。但是这个CMultiPaneFrameWnd类型对象是MFC框架自动创建,就需要找到是否可以在创建时候改变对象类型,使之创建自己定义的继承对象,跟踪MFC框架后结果是可行的,因为框架里也是根据类型在运行时创建的。具体做法如下:

新建一个类继承CMultiPaneFrameWnd,映射OnMouseMove消息,把DECLARE_DYNAMIC(CLASSNAME)替换

DECLARE_SERIAL(CLASSNAME),

IMPLEMENT_DYNAMIC(CLASSNAME,CMultiPaneFrameWnd)替换为

IMPLEMENT_SERIAL(CLASSNAME,CMultiPaneFrameWnd,VERSIONABLE_SCHEMA| 2)

在OnMouseMove里try catch子类的OnMouseMove就行了。

在组件创建CDockablePane对象的时候注入运行时类

m_pMiniFrameRTC = RUNTIME_CLASS(CLASSNAME);想得到这个

CLASSNAME对象那就重写CreateDefaultMiniframe方法,这样每个组件都做一遍,那样CDockablePane拖动就不会出现上述那个问题。当两个CDockablePane拖动到一起又会出现“遇到不适当参数问题”,原因是这时MFC框架在这种情况下创建不是CMultiPaneFrameWnd对象,而是CTabbedPane对象,方法的原理是一样的,注入运行时对象,放到Create方法里。这就要重写这个方法了。

问题2、拖动各个组件浮动于控件之上,关闭IE会导致崩溃。

这是因为CFrameWndEx的DockingManager类在CFrameWndEx销毁时候也被销毁了,而浮动组件销毁时候,在销毁之前要用到这个成员,这样就导致访问非法地址了(野指针)。在应用程序中,CFrameWndEx是主窗口,所以销毁都是在各个组件销毁之后,但OCX的CFrameWndEx是子窗口,销毁顺序就不确定了。这就要求程序显式的销毁各组件资源。

问题3、有个组件是工具条控件,继承与MFCTOOLBAR,发现按钮变灰。

这是因为有些Windows消息没到MFCTOOLBAR控件。这是因为这些控件的父窗口是子窗口,子窗口没有自己消息泵,所以没有传递下来。网上提供办法有通过HOOK Windows消息,或者创建一个主窗口继承CWnd,隐藏这个窗口,把相关的消息映射到这个窗口上,这个窗口回调相应的控件的处理函数。

工具条的TIP消息,这个是因为控件没有OnIdle,这就要求自己模拟OnIdle,还有TIP消息。模拟TIP消息可在OnMouseMove消息里调用RelayEvent。

框架外的问题:

问题1:用动态链接方式,如果有依赖的相关DLL,要注意“工作目录”问题,DLL搜索路径根据系统不同而有不同的表现,采用临时设置工作目录,加载完成后,恢复原来的工作目录。SetCurrentDirectory,GetCurrentDirectory,如果被其它进程所加载的模块也会出现类似情况。工作目录将不会当前程序路径。

问题2:在局部函数里声明的类型,不能返回引用,因为这些类型生命周期在函数结束后终止,如果返回引用,将是不确定的内存地址。

问题2:SetWindowPos和MoveWindow的区别。

问题3:OCX控件对象被IE多个标签页共享,在一些功能的表现中会导致程序不稳定性,最好的接口调用模式是

如下,控件里的功能组件不保存自身对象引用,调用时候外部负责传入

调用对象参数。组件内部负责处理相应的功能处理。这样很好解决了OCX共享问题。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: