MFC工程转Win32总结.docx

上传人:b****3 文档编号:4468273 上传时间:2022-12-01 格式:DOCX 页数:24 大小:247.48KB
下载 相关 举报
MFC工程转Win32总结.docx_第1页
第1页 / 共24页
MFC工程转Win32总结.docx_第2页
第2页 / 共24页
MFC工程转Win32总结.docx_第3页
第3页 / 共24页
MFC工程转Win32总结.docx_第4页
第4页 / 共24页
MFC工程转Win32总结.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

MFC工程转Win32总结.docx

《MFC工程转Win32总结.docx》由会员分享,可在线阅读,更多相关《MFC工程转Win32总结.docx(24页珍藏版)》请在冰豆网上搜索。

MFC工程转Win32总结.docx

MFC工程转Win32总结

MFC工程转Win32总结

--2014.7byzzx

0、将MFC工程转成Win32工程的原因

(1)因为TrueLink的主工程及相关子工程,已经使用基于Win32的duilib界面库,不在需要依赖MFC实现界面效果,而且duilib能实现远好于MFC的UI效果,也能解决MFC窗口过多带来的gdi句柄过多的问题。

(2)再者是,如果使用MFC,在程序启动时会将mfc库mfc100.dll和mfc100u.dll(Unicode版本的MFC库),载入到进程中,会占用TrueLink一定的内存。

另外这两个库大小大约8MB多一点,如果将这两个库去掉,也能有效的减小安装包的大小。

同时也能有效减小在线升级包的大小,有效的提升在线升级的效率。

(3)除了将TL上层的相关工程去掉对MFC的依赖,也要将网络媒体层和平台层的相关工程去除对MFC的依赖,因为这些底层的库不涉及到界面,完全用不到MFC。

1、Win32改造的一般步骤

(1)在工程设置中将,将MFC的使用,改为使用标准Windows库

(2)将stdafx.h中包含MFC头文件的语句(头文件名一般以afx开头)删除,添加win32工程要包含的头文件:

//Windows头文件:

#include

//C运行时头文件

#include

#include

#include

#include

(3)关于errorC2065:

“DEBUG_NEW”:

未声明的标识符->直接将cpp文件中的如下代码删除:

#ifdef_DEBUG

#definenewDEBUG_NEW

#undefTHIS_FILE

staticcharTHIS_FILE[]=__FILE__;

#endif

(4)MFC常用宏替换

1)TRACE是MFC的,可以用OutputDebugString替代

2)ASSERT是MFC的,可以用小写的assert替代,要包含#include

3)“_T”:

找不到标识符,添加头文件tchar.h

4)LPCSTR:

找不到标识符,添加头文件windows.h

5)VERIFY:

改成assert

例如:

VERIFY(FindClose(hFind));

--》

BOOLbRet=FindClose(hFind);

assert(bRet);

6)AfxIsValidAddress改为CString头文件中的IsValidAddress

AfxIsValidAddress改为CString头文件中的IsValidAddress

7)TRY...CATCH....换为try...catch...

(5)新建一个mfc工程和一个win32工程,对比一下testwin32.vcxproj文件,对比testwin32.rc文件,参照区别手动修改,以win32工程为准

2、网络库头文件的包含问题

1>c:

\programfiles\microsoftsdks\windows\v7.0a\include\winsock2.h(1619):

errorC2375:

“closesocket”:

重定义;不同的链接

1>c:

\programfiles\microsoftsdks\windows\v7.0a\include\winsock.h(752):

参见“closesocket”的声明

1>c:

\programfiles\microsoftsdks\windows\v7.0a\include\winsock2.h(1638):

errorC2375:

“connect”:

重定义;不同的链接

1>c:

\programfiles\microsoftsdks\windows\v7.0a\include\winsock.h(754):

参见“connect”的声明

1>c:

\programfiles\microsoftsdks\windows\v7.0a\include\winsock2.h(1659):

errorC2375:

“ioctlsocket”:

重定义;不同的链接

1>c:

\programfiles\microsoftsdks\windows\v7.0a\include\winsock.h(759):

参见“ioctlsocket”的声明

1>c:

\programfiles\microsoftsdks\windows\v7.0a\include\winsock2.h(1680):

errorC2375:

“getpeername”:

重定义;不同的链接

1>c:

\programfiles\microsoftsdks\windows\v7.0a\include\winsock.h(764):

参见“getpeername”的声明

但凡在Windows平台下用C++做网络开发很多时候都会同时包含这两个头文件,如若顺序不当(windows.h先于winsock2.h)就会出现很多莫名其妙的错误。

要注意先后顺序,如下:

#include

#include

3、MFC的CImage文件引起的CString不明确的问题

1>e:

\svn_dir\20140519_truelink_v2r6_sp1\90-truelink\common\include\picture.h(40):

errorC2872:

“CImage”:

不明确的符号

1>可能是“e:

\svn_dir\20140519_truelink_v2r6_sp1\90-truelink\kdvp_pcmtim\minimfc\include\cimage.h(85):

CImage”

1>或“d:

\programfiles\microsoftvisualstudio10.0\vc\atlmfc\include\atlimage.h(68):

ATL:

:

CImage”

1>e:

\svn_dir\20140519_truelink_v2r6_sp1\90-truelink\common\include\imtcpicmanager.h(36):

errorC2872:

“CString”:

不明确的符号

1>可能是“e:

\svn_dir\20140519_truelink_v2r6_sp1\90-truelink\kdvp_pcmtim\minimfc\include\cstring.h(33):

CString”

是因为使用到CImage的地方包含了mfc的atlimage.h的头文件,而atlimage.h中包含了atlstr.h的头文件,所以出现CImage和CString不明确的符号的问题。

所以不能包含atlimage.h,minimfc中既实现了CString,也实现了CImage,直接包含minimfc.h即可。

4、duilib包含minimfc.h头文件问题

(1)duilib中使用到了CImage,改为依赖minimfc,会出现Cimage不明确问题。

包含的是atlimage.h,将值改为cimage.h后,CString还是不明确。

(2)是因为duilib中使用到了atl中的CTime,包含了atltime.h,这个头文件又包含了atlstr.h即atl的CString的头文件,所以出现CString不明确问题。

Minimfc中也实现了CTime,所以不用使用ATL的CTime。

(3)但是CImage还会报错,因为stdafx.h中包含了uilib.h,后包含了minimfc.h,应该将顺序调整一下,先包含minimfc.h。

5、ATL的CString与MFC的CString区别

(1)ATL的CString对应的是atlstr.h头文件:

D:

\ProgramFiles\MicrosoftVisualStudio10.0\VC\atlmfc\include\atlstr.h,定义如下:

#ifndef_ATL_CSTRING_NO_CRT

typedefCStringT>>CAtlStringW;

typedefCStringT>>CAtlStringA;

typedefCStringT>>CAtlString;

#else//_ATL_CSTRING_NO_CRT

typedefCStringT>CAtlStringW;

typedefCStringT>CAtlStringA;

typedefCStringT>CAtlString;

#endif//_ATL_CSTRING_NO_CRT

#ifndef_AFX

typedefCAtlStringWCStringW;

typedefCAtlStringACStringA;

typedefCAtlStringCString;

#endif

(2)MFC的CString对应的是afxstr.h头文件:

D:

\ProgramFiles\MicrosoftVisualStudio10.0\VC\atlmfc\include\afxstr.h,定义如下:

#endif//_MFC_DLL_BLD

typedefATL:

:

CStringT>CStringW;

typedefATL:

:

CStringT>CStringA;

typedefATL:

:

CStringT>CString;

#else

typedefATL:

:

CStringT>CStringW;

typedefATL:

:

CStringT>CStringA;

typedefATL:

:

CStringT>CString;

#endif//!

_WIN64&&_AFXDLL

(3)由于两种CString的实现都在头文件中,即函数的实现都放在类的头文件中,所以可以直接包含头文件来引用。

这两种CString的相互关系可以参考如下的链接:

6、静态变量定义执行先后顺序问题

(1)相关说明

1)进程启动后,要执行一些初始化代码(如一些全局及静态变量的空间分配和赋初值、全局及静态对象的构造等等),然后跳转到相关main函数执行。

2)对于MFC工程,如果要看从初始化的操作,到main函数的执行,到CWinThread如何将App的InitInstance、Run与win32的工程的执行步骤对应起来的(窗口类的注册、窗口的创建、消息循环读取并分发消息),直接在App的InitInstance中添加断点,然后调试运行查看调用堆栈即可看出。

(2)问题说明并解决

1)但是多个静态对象都存在时,在构造时,由于相互的依赖关系,必须要有个先后顺序,否则可能会产生异常。

2)通过调试运行发现,duilib中的CSkinShadow类定义了CImage静态对象,运行时会优先于CImage:

:

s_initGDIPlus,进入CImage的构造函数,进而调用s_initGDIPlus.IncreaseCImageCount函数,访问到未经初始化的关键代码段对象m_sect,从而引起崩溃。

由于都是静态变量定义,执行的先后顺序无法预料,正是CSkinShadow类定义了CImage静态对象定义先执行,CImage:

:

s_initGDIPlus的定义后执行,导致上面的问题。

所以要保证代码正常执行,要使CImage:

:

s_initGDIPlus的定义先执行。

所以此处参考MFC中的处理办法,使用#pragmainit_seg(lib),保证先执行。

3)MFC中的Cimage类的代码都放置在对应的头文件中,即成员函数都以内联的方式放置在头文件中。

Cimage类中使用到两个static对象,在头文件中只有声明,好像找不到静态对象的定义。

在构造函数中打上断点,通过查看调用堆栈,找到了定义处,也找到了本问题的解决办法:

#include"StdAfx.H"

#pragmawarning(disable:

4073)//initializersputinlibraryinitializationarea

namespaceATL

{

#pragmainit_seg(lib)

CImage:

:

CDCCacheCImage:

:

s_cache;

};//namespaceATL

使用了#pragmainit_seg(lib),就能保证CImage:

:

s_cache的构造在CImage对象构造之前构造,保证了构造顺序,从而能够正常执行。

相关代码及注释如下所示:

(3)MFC源码查看

如果直接能Go过去就比较好。

如果Go不过去如何查看呢?

通过添加断点,查看调用堆栈。

如果是一个类的话,要查看CPP相关源码,可以先定义一个对象,通过构造时要调用构造函数的特性,在构造的语句上添加断点,查看调用堆栈,进入对应的CPP文件,进而找到相关的函数实现。

7、友元函数也需要导出

(1)minimf工程从VC6的MFC中抽出了CString类,类中定义了友元函数,是重载了加号操作符,重载函数就是友元函数,如下所示:

friendCStringAFXAPIoperator+(constCString&string1,

constCString&string2);

friendCStringAFXAPIoperator+(constCString&string,TCHARch);

friendCStringAFXAPIoperator+(TCHARch,constCString&string);

#ifdef_UNICODE

friendCStringAFXAPIoperator+(constCString&string,charch);

friendCStringAFXAPIoperator+(charch,constCString&string);

#endif

friendCStringAFXAPIoperator+(constCString&string,LPCTSTRlpsz);

friendCStringAFXAPIoperator+(LPCTSTRlpsz,constCString&string);

但在外部调用时,即

CStringstrTest=strPath+strName;

链接时提示错误,找不到operate+函数。

(2)友元用的比较少,后经查阅资料才知道,友元函数是可以直接访问类的私有成员的非成员函数。

它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend。

类似于全局函数,外部如果要使用需要单独导出(虽然CString类导出了,但是友元函数不属于类,所以需要单独导出)。

所以上述函数都是要导出的。

8、updateinstall在链接libminimfc库时老是出现无法解析的外部符号的问题

是因为链接路径弄错了,导致链接的是老的libminimfc.lib库,出现链接异常问题。

9、去除changelang对minimfc的依赖,尽量使changelang独立

(1)尽量减少库与库之间的耦合,之前处理imageoleex工程时也是这么个想法,能做到相互独立的,尽量做到相互独立,不相互依赖。

(2)工程中使用到了两个MFC类:

CString和CFile类,对于CString直接使用stl的string类替换;对于CFile,则使用API替换,具体API的参数设置,可参见CFile相关函数内部实现。

1)使用stl的string:

#include

usingnamespacestd;

#ifdef_UNICODE

typedefwstringtstring;

#else

typedefstringtstring;

#endif

在使用时,调用c_str()函数来得到LPCTSTR类型的数据。

再就是string不支持format格式化,可以使用C函数_stprintf()来格式化。

2)用API函数替换CFile:

(之所以替代CFile,目的是不想依赖minimfc库)

HANDLEhFile=:

:

CreateFile(strPathName.c_str(),GENERIC_READ,0,NULL,

OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

if(hFile==INVALID_HANDLE_VALUE)

{

returnFALSE;

}

DWORDdwSize;

dwSize=:

:

GetFileSize(hFile,NULL);

u8*pBuf=newu8[dwSize];

DWORDdwReadBytes=0;

:

:

ReadFile(hFile,pBuf,dwSize,&dwReadBytes,NULL);

if(dwReadBytes==0)

{

delete[]pBuf;

:

:

CloseHandle(hFile);

returnFALSE;

}

:

:

CloseHandle(hFile);

(3)在添加stl的string的头文件包含后,出现如下的错误:

对于extent,有两处都定义了,出现冲突。

在zip.cpp中,定义了:

typedefsize_textent;

解决办法有两种:

1)直接将zip.cpp中的extent类型直接换成size_t;

2)是stdafx.h中包含了#include引起的,由于zip.cpp是开源拷贝过来的文件,不需

要包含stdafx.h,所以可以在工程中设置:

.c(或.cpp)文件点右键选择Properties,在PrecompiledHeaders项下设置NotUsingPrecompiledHeaders即可,如下所示:

具体原理说明参见:

(4)pcdvdll使用stl的string/wstring引起的TL的崩溃(2014/08/08)

1)需要将pcdvdll改造成win32的工程,但其中使用到了CString类,为了不引入对minimfc的依赖,让pcdvdll尽量独立,决定使用stl的string/wstring。

修改了一些全局函数的返回值为tstring,结果就是因为这样引起了pcdvdll的崩溃,从而引起TL的崩溃。

如下所示:

tstringGetPcdvEventName(u16wEvent);

tstringGetErrorCodeDes(u16wError);

2)在使用string中存放的字符串内容时,都要调用.c_str()方法。

一般我们不会逐一去检查,而是通过编译器去检查(参数类型检查),如有问题则会报错,在报错的地方去修改。

但是对于使用可变长参数的函数,则不进行类型检测,如果直接调用,则可能引起崩溃。

Pcdvdll的崩溃代码如下:

voidCMtInst:

:

NotifyUI(u16wMsg)

{

HWNDhWnd=g_cMtSsn.GetMainWnd();

if(hWnd!

=NULL&&:

:

IsWindow(hWnd))

{

dvPrint("[NotifyUI]msg%s(%d),errcode=%d(%s),len=%d\n",

OspEventDesc(wMsg),

wMsg,

g_cUIMsg.GetErrorCode(),

GetErrorCodeDes(g_cUIMsg.GetErrorCode()),

g_cUIMsg.GetMsgBodyLen());

:

:

SendMessage(g_cMtSsn.GetMainWnd(),wMsg,(WPARAM)&g_cUIMsg,NULL);

//清空缓存

g_cUIMsg.SetMsgBody();

}

}

 

voidCPcdvCfg:

:

SendMsgToMtSsnDaemon(u16wEvent,constu8*constpbyMsg,u16wLen)

{

dvPrint("[CPcdvCfg:

:

SendMsgToMtSsnDaemon]wEvent%s(%d),wLen=%d\n",GetPcdvEventName(wEvent),wEvent,wLen);

:

:

OspPost(MAKEIID(AID_MT_PCDUALVIDEO,CInstance:

:

DAEMON),wEvent,pbyMsg,wLen);

}

 

voiddvPrint(s8*pszFmt,...)//可变长参数,不进行类型检测

{

s8achPrintBuf[255];

s32nBufLen=sprintf(achPrintBuf,"[dvPrint]");

va_listtArgptr;

va_start(tArgptr,pszFmt);

vsprintf(achPrintBuf+nBufLen,pszFmt,tArgptr);

va_end(tArgptr);

if(g_cMtSsn.IsPrintf())

{

OspPrintf(TRUE,FALSE,achPrintBuf);

}

dvLog(achPrintBuf);

}

所以,在使用到stl的string的工程中,一方面通过编译器去检测,另一方要特别小心可变长参数的函数,要对

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 公共行政管理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1