分享

VC6向VC9 移植时常见BUG 2

 Daisycv 2010-11-19
五、.def文件引起的连接告警

  对于普通的DLL项目中使用的.def文件通常会引起LNK4017链接告警,如下所示:

  .ComFunc.def(4) : warning LNK4017: DESCRIPTION statement not supported for the target platform; ignored

  Creating library ...Debug/ComFunc.lib and object ...Debug/ComFunc.exp

  一个典型的.def文件通常有以下内容:

  LIBRARY "XorCryptor"

  DESCRIPTION 'XorCryptor Windows Dynamic Link Library'

  EXPORTS

  ; Explicit exports can go here

  ..................

  消除这个连接告警的方法就是从.def文件中删除DESCRIPTION描述信息,不过这个告警也不是什么大问题,不删也可以。另一个可能产生的连接告警是LNK4222,通常出现在ocx控件和com组件的项目中,一个典型输出是:

  Linking...

  .PlusInModule.def : warning LNK4222: exported symbol 'DllCanUnloadNow' should not be assigned an ordinal

  .PlusInModule.def : warning LNK4222: exported symbol 'DllGetClassObject' should not be assigned an ordinal

  .PlusInModule.def : warning LNK4222: exported symbol 'DllRegisterServer' should not be assigned an ordinal

  .PlusInModule.def : warning LNK4222: exported symbol 'DllUnregisterServer' should not be assigned an ordinal

  出现这个告警的原因是旧的项目的.def文件通常这样定义ocx和com必需的四个导出函数:

  EXPORTS

  DllCanUnloadNow @1 PRIVATE

  DllGetClassObject @2 PRIVATE

  DllRegisterServer @3 PRIVATE

  DllUnregisterServer @4 PRIVATE

  其中为这四个重要的导出函数指定了四个顺序号。Windows平台上通常用两种方式定位DLL文件中的导出函数,一种是根据导出函数名称,一种是根据顺序号,上学时曾经写过一个显示图片的程序,能处理大多数当时流行的图像格式文件,唯独jpeg格式的搞不定,有一次看到一个图像处理软件中包含了一个LoadJpeg.dll,很显然这个DLL是处理jpeg格式的图像文件的嘛,于是赶快用depends look了一下,顿时高喊:鬼啊~~~。原来这个depends竟然查不到导出函数的名字,后来才知道还有NONAME参数强制用顺序号定位导出函数,于是就常常弄个没有导出函数名字的DLL到处show。。。。嗯,又扯远了。话说为什么旧的系统要以此指定这四个导出函数的顺序号我就没有研究了,反正现在不需要指定了,只要将@1,@2之类的删除就行了,不过不删好像也没什么问题,它们会被自动忽略。

  六、使用MFC的消息映射宏引起的编译错误

  错误现象之一:

  f:project.....plusmaindlg.cpp(220) : error C2440: 'static_cast' : cannot convert from 'void (__thiscall CPlusMainDlg::* )(int,BOOL)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'

  None of the functions with this name in scope match the target type

  错误现象之二:

  f:project.....crpfileopavdlg.cpp(87) : error C2440: 'static_cast' : cannot convert from 'LRESULT (__thiscall CCrpFileOpavDlg::* )(LPCTSTR,int)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'

  None of the functions with this name in scope match the target type

  以上两个编译错误产生是因为新旧版本的MFC 中对ON_MESSAGE消息映射宏定义不同引起的,先看看老版本的MFC的ON_MESSAGE消息宏定义:

  #define ON_MESSAGE(message, memberFxn)

  { message, 0, 0, 0, AfxSig_lwl,

  (AFX_PMSG)(AFX_PMSGW)(LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM))&memberFxn },

  再看看新版本的ON_MESSAGE定义:

  #define ON_MESSAGE(message, memberFxn)

  { message, 0, 0, 0, AfxSig_lwl,

  (AFX_PMSG)(AFX_PMSGW)

  (static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) >

  (memberFxn)) },

  注意,函数类型没有变化,都是:

  LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM);

  类型的函数指针(CWnd以及派生类的类成员函数指针),区别之处是新的ON_MESSAGE宏使用C++的 static_cast 操作符代替了C类型的强制转换。产生这两个错误其实是因为用户没有按照ON_MESSAGE宏的约定声明和定义消息响应函数造成的,比如,对于某些不需要处理返回值的消息响应函数,用户通常这样声明和定义消息响应函数:

  在头文件中声明:

  afx_msg void OnFileProcess(WPARAM wParam,LPARAM lParam);

  在源文件中实现:

  void CCrpFileOpavDlg::OnFileProcess(WPARAM wParam, LPARAM lParam)

  {

  .......

  }

  或者更过分一些,直接指定为实际参数类型:

  在头文件中声明:

  afx_msg void OnFileProcess(LPCTSTR lpszMessage, int nPercent);

  在源文件中实现:

  void CCrpFileOpavDlg::OnFileProcess(LPCTSTR lpszMessage, int nPercent)

  {

  .......

  }

  旧版本的ON_MESSAGE使用了C类型的强制转换,宏解开后的代码后不会产生错误信息,但是改成对类型检查很严格的static_cast 操作符时就出问题了,因为通不过static_cast 操作符的检查。解决方法就是修改代码,同时吸取教训,普遍使用的方法并不一定就能约定俗成,一切还是要按照规矩来。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多