一个23万行代码的移植过程

一个23万行代码的移植过程

一、概述
移植完毕后觉得难度并不高,遇到了一些困难,都能顺利解决,最难得是不同编译器之间的差异造成的程序运行结果不同,比如这次移植遇到的内存管理是遇到的主 要问题,有一块内存在vc6下正常,到vc8-debug下就总溢出,vc8-release下又好了,最后大家讨论一下,只好归咎于编译器(BILL GATE的错),此问题暂时用简单的条件控制暂时解决,没有全部解决。

移植分几个阶段,第一步打开.dsw工程,vc8会自动形成.sln,以后就用这个了;第二步配置环境,include,lib目录什么的;第三步编译一 下,总体看看,写得比较好的代码一般错误很少,比如我移植的代码分为34 个子工程,有个工程的只有一个错误,其他都是警告。第四步,修改了所有的错误后就可以编译、链接了,不过一般这个时候还是不能运行的,因为好多警告还是要 改的。第五步,最后一步是最难过的,成功失败在此一举,调试运行总是很刺激,不过vc6的mfc貌似还是和vc8的有些不同,所以出了错还是要一步一步地 跟踪的,这一步只遇到一个致命问题,最后再讲。

PS:需要强调的是,警告比错误更危险,一定要注意。


二、具体实施
1、配置好环境后先看看(all)工程都包括那些子工程

其中主要依赖关系包括:

第一级的Project all包括:
Project_Dep_Name CPM
Project_Dep_Name scanner
Project_Dep_Name PowerMonitor
Project_Dep_Name HostDiag
Project_Dep_Name DICOMApp

第二级的Project scanner又包括:
Project_Dep_Name EHWemu
Project_Dep_Name ustream
Project_Dep_Name usi_mon_emu
Project_Dep_Name udl
Project_Dep_Name uos


2、从第三级(底层)的uos.dsp开始
编译了一下,只有1 error(s), 14 warning(s),自然先对付错误了:


症状1 //error C2668: 'log10' : ambiguous call to overloaded function
这个容易,vc6下代码这样(DWORD)log10(*((DWORD *)pValue))+2 > dwValueLength )

vc8下看下log10的声明 double __cdecl log10(__in double _X);
改一下!(double)log10(*(double *)pValue)+2 > dwValueLength )


症状2 //warning C4996: 'sscanf' was declared deprecated
这个问题很普遍,就是vc8对原来的很多不安全的函数都发不了_s版本。
直接改为 sscanf_s( pBuff, "%d", &dwDebugFlag ); 参数都没变,真好。


症状3 // _controlfp( puthThread->dwFPControl, MCW_PC );
这个麻烦一点,需要多个参数,那就定义一个unsigned int control_word;
然后改成 _controlfp_s(&control_word,puthThread->dwFPControl, MCW_PC );

类似的包括FILE *pFile = fopen( "1.txt", "wt" );
改为//errno_t err; err = fopen_s(&pFile ,"1.txt", "wt" ););


症状4 // warning C4532: 'return' : jump out of __finally block has undefined behavior during termination handling
说你返回值路径不全面,加几个return就Ok了。

其他不一一列举,都是_s函数的问题,至此一个最简单的工程就搞定了,以下的工程遇到同样问题就不再描述了。




3、借助下一个工程来说一个老问题。
//error C2065: 'i' : undeclared identifier
在这一行 for(i = 0; i < iMaxFocalZones; i++)
其实i是在 for(int i = 0; i < iMaxFocalZones; i++) 定义的
改也容易 把int i 提出来就可以了,不过要仔细察看i的作用域,不要提错了,就大发了。

'atan' : ambiguous call to overloaded function 这个地方我偷懒了。
#define PI (4 * atan(1)) 改为 #define PI 3.1415926535897932384626433832795。 呵呵


4、其他几个问题有雷同,就不讲了,下面来个难度高的!!
//error C2906: 'const AFX_MSGMAP *CDlgInterface::GetThisMessageMap(void)' : explicit specialization requires 'template <>'
MFC的一个宏出了问题,说DIALOG_INST少了个template <>。
DIALOG_INST 定义如下:

#define DIALOG_INST(T, DLG) /
/
BEGIN_MESSAGE _MAP( CDlgInterface, CDialogPlus ) /
/*{{AFX_MSG_MAP(CDlgInterface)*/ /
ON_BN_CLICKED(IDC_Apply, OnApply) /
ON_WM_WINDOWPOSCHANGING() /
/*}}AFX_MSG_MAP*/ /
END_MESSAGE_MAP()


template <>应该放哪里呢?
查了查MSDN,区别不在DIALOG_INST的定义,继续往里深入,原来差在BEGIN_MESSAGE_MAP的定义。


#define BEGIN_MESSAGE_MAP(theClass, baseClass) /
PTM_WARNING_DISABLE /
const AFX_MSGMAP* theClass::GetMessageMap() const /
{ return GetThisMessageMap(); } /
const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() /
{ /
typedef theClass ThisClass; /
typedef baseClass TheBaseClass; /
static const AFX_MSGMAP_ENTRY _messageEntries[] = /
{
改为
#define BEGIN_MESSAGE_MAP_TPL(theClass, baseClass) /
PTM_WARNING_DISABLE /
template <> const AFX_MSGMAP* theClass::GetMessageMap() const /
{ return GetThisMessageMap(); } /
template <> const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() /
{ /
typedef theClass ThisClass; /
typedef baseClass TheBaseClass; /
static const AFX_MSGMAP_ENTRY _messageEntries[] = /
{
DIALOG_INST重新定义一下:
#define DIALOG_INST(T, DLG) /
/
BEGIN_MESSAGE_MAP_TPL( CDlgInterface, CDialogPlus ) /
/*{{AFX_MSG_MAP(CDlgInterface)*/ /
ON_BN_CLICKED(IDC_Apply, OnApply) /
ON_WM_WINDOWPOSCHANGING() /
/*}}AFX_MSG_MAP*/

恩,就这样了。自己看看就知道了,mfc也在慢慢的改变,不过改动不大。



5、error C2039: 'ReadHuge' : is not a member of 'CFile,这个容易,readhuge早被read包括了。


6、还是mfc的问题
'static_cast' : cannot convert from 'void (__thiscall CCPMView::* )(WPARAM,LPARAM)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
定位到ON_MESSAGE(WM_USI_CREATE_DIALOG, OnUSICreateDialog)。

这是ms自己的问题,原来mfc对返回值要求不严,现在要求必须是LRESULT,只好用各函数调转一下。
用 ON_MESSAGE(WM_USI_SYS_STATEACTIVITY_CHANGE, OnSysStateActivityChange1)
代替 ON_MESSAGE(WM_USI_SYS_STATEACTIVITY_CHANGE, OnSysStateActivityChange)


LRESULT CCPMView::OnSysStateActivityChange1(WPARAM eSysState, LPARAM eSysActivity)
{
OnSysStateActivityChange((ESysState) eSysState,(ESysActivity) eSysActivity);
return 1;
}
来hook OnSysStateActivityChange一下,hook一下是最简单的办法,其他方法更绕远。



7、error C2593: 'operator +=' is ambiguous
定位到 m_strDist += iKey;
类型不匹配造成的,强制转换一下。 m_strDist = m_strDist + (char)iKey; OK!!


8、error C2514: 'LPCTSTR' : class has no constructors
定位到 bsStep.sLabel = LPCTSTR(*(m_aDialogStepData.pstLabel));
又是vc6不严格的问题,本来是想转换一下类型,结果LPCTSTR的定义由(typedef CONST CHAR *LPCSTR, *PCSTR;
)改变为(typedef __nullterminated CONST CHAR *LPCSTR, *PCSTR;
)。

那就强制一下好了,加个括号。bsStep.sLabel = (LPCTSTR)(*(m_aDialogStepData.pstLabel));


9、(CFrameWnd*)AfxGetMainWnd()出现了严重的问题。
没有出现编译错误的情况下,(CFrameWnd*)AfxGetMainWnd()返回空指针,我的工程是多线程的,多达20个线程一起跑,根本无法确 定位置,其实这样的情况最烦人了,调试了将近两天才确定位置,幸好程序本身有很强大的日志系统,日志是多线程开发必须要考虑的部分。


10、内存溢出的问题。
内存溢出并不能总被发现,release下的正常情况,debug未必正常,这次就遇到了一个数组开小了的情况,vc6下也溢出了,不过居然没出 错,vc8 下就不行了,总是内存越界提醒(bad pointer),只好一点一点找,最后发现了一个二维数组的问题,改了之后再没有错误了。

过了最后一关,整个移植就完成了,居然没什么错误,最后大家也不怪bill gate了。
很多类似的错误没有一一列举,希望大家触类旁通,多查查资料就好了。



三、一些技巧
1、可以vc6,vc8同时开着,有利于进行对比监控,经常是用f10一句一句运行对比,特别有利于调试错误数据。
2、用Beyond Compare 2对比vc6、vc8的工程,有利于发现不正确的修改。
3、多翻阅msdn,最好的参考就是msdn,把C2039编号直接检索一下,就知道是什么错误了,而且有很多如何修改的建议。
4、每天改动之前,先做备份,省得改错了。



四、总结
看来vc6移植到vc8可行性很好,这次大规模的移植证明了这一点。
移植的关键是对程序的理解,以前把vc6移植到BCB的时候基本上是做翻译的工作,好比英语翻译为汉语,只要理解了程序就好办,不过还是要感慨一下,微软作的很不错了,我这次移植基本上没遇到大的障碍,多亏微软了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值