正在阅读:经典编程:DLL地狱及其解决方案经典编程:DLL地狱及其解决方案

2004-05-17 10:05 出处:CSDN 作者:happydeer(翻译) 责任编辑:linjixiong
#endif // defined(DLL_EXAMPLE_MODIFIED)      class DLL_PREFIX CExample{   public:    CExample(){mpHandler = 0;}    virtual ~CExample(){}    virtual void DoCallBack(int event) = 0;    ICallBack * SetCallBackHandler(ICallBack *handler);    void Run();   private:    ICallBack * mpHandler;   };      很显然,为了给扩展DLL的导出类(增加新的虚函数)提供方便,我们必须做如下工作:   1. 增加ICallBack * SetCallBackHandler(ICallBack *handler);函数;   2. 在每个导出类的定义中增加相应的指针;   3. 定义3个宏;   4. 定义一个通用的ICallBack接口。      为了演示给CExample类增加新的虚回调函数,我在这里增加了一个ICallBack01接口的定义。很显然,新的虚回调函数应该加在新的接口中。每次DLL更新都新增一个接口(当然,每次DLL更新时,我们也可以给一个类同时增加多个虚回调函数)。      注意,每个新接口必须从上一个版本的接口继承。在我的例子中,我只定义了一个扩展接口ICallBack01。如果DLL再下个版本还要增加新的虚回调函数,我们梢栽诙ㄒ逡桓鯥CallBack02接口,注意ICallBack02接口要从ICallBack01接口派生,就跟当初ICallBack01接口是从ICallBack接口派生的一样。      上面代码中还定义了几个宏,用于定义需要检查接口版本的函数。例如我们要为新接口ICallBack01增加新函数DoCallBack01,如果我们要调用ICallBack * mpHandler; 成员的话,就应该在CExample类进行一下检查。这个检查应该如下实现:      if(mpHandler != NULL && mpHandler->GetObjectUIID()>=ICallBack01::GetClassUIID()){    ((ICallBack01 *) mpHandler)->DoCallBack01(2);   }      我们看到,新回调接口增加之后,在CExample类的实现中只需简单地插入新的回调调用。      现在你可以看出,我们上述对DLL的改动并不会影响客户应用程序。唯一需要做的,只是在采用这种新设计后的第一个DLL版本(为DLL导出类增加了宏定义、回调基本接口ICallBack、设置回调处理的SetCallBackHandler函数,以及ICallBack接口的指针)发布后,应用程序进行一次重编译。(以后扩展新的回调接口,应用程序的重新编译不是必需的!)      以后如果有人想要增加新的回调处理,他就可以通过增加新接口的方式来实现(向上例中我们增加ICallBack01一样)。显然,这种改动不会引起任何问题,因为虚函数的顺序并没有改变。因此应用程序仍然以以前的方式运行。唯一你要注意的是,除非你在应用程序中实现了新的接口,否则你就接收不到新增加的回调调用。      我们应该注意到,DLL的用户仍然能够很容易与它协同工作。下面是客户程序中的某个类的实现例子:      // 如果DLL_EXAMPLE_MODIFIED没有定义,使用以前版本的DLL   #if !defined(DLL_EXAMPLE_MODIFIED)   // 此时没有使用扩展接口ICallBack01   class CClient : public CExample{   public:    CClient();    void DoCallBack(int event);   };      #else // !defined(DLL_EXAMPLE_MODIFIED)   // 当DLL增加了新接口ICallBack01后,客户程序可以修改自己的类   // (但不是必须的,如果他不想处理新的回调事件的话)   class CClient : public CExample, public ICallBack01{   public:    CClient();    void DoCallBack(int event);       // 声明DoCallBack01函数(客户程序要实现它,以处理新的回调事件)    // (DoCallBack01是ICallBack01接口新增加的虚函数)    void DoCallBack01(int event);   };   #endif // defined(DLL_EXAMPLE_MODIFIED)      例程 ---> 代码下载(6.26K)      与本文的内容配套,我提供了演示程序Dll_Hell_Solution。      1. Dll_example: DLL的实现项目;   2. Dll_Client_example: DLL的客户应用程序项目。      注意:目前Dll_Hell_Solution/Dll_example/dll_example.h文件中的DLL_EXAMPLE_MODIFIED定义被注释掉了。如果放开这个注释,可以生成更新后的DLL版本;然后可以再次测试客户应用程序。      为了保证读者能够正常演示,请遵循如下步骤:   1. 不要改动任何代码(此时DLL_EXAMPLE_MODIFIED没有定义)编译Dll_example和Dll_Client_example两个项目。运行客户程序,体验最初的情况。   2. 放开DLL_EXAMPLE_MODIFIED的注释,然后重新编译Dll_example。重新运行客户程序(此时使用了新版本的DLL),应该仍然运行正常。   3. 重新编译Dll_Client_example,生成新的客户程序。我们看到新增加的回调函数被调用了!
察看评论详细内容 我要发表评论
作者笔名 简短内容 发表时间
:
键盘也能翻页,试试“← →”键

关注我们

最新资讯离线随时看 聊天吐槽赢奖品