免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1953 | 回复: 0
打印 上一主题 下一主题

ACE_常见问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-16 16:57 |只看该作者 |倒序浏览
   我是个ACE菜鸟,前一阵子头痛于万事开头难的问题,很多问题相当SB,不过考虑到很多初学者和我一样被老板骂得焦头烂额,这里还是把学习 ACE第一周遇到的问题贴上来,希望对刚刚接触ACE的鸟伴有所帮助(-:1、解决5.6版本的ACE使用 ACE_HAS_MFC 后提示WIN32_NT版本过低的问题。
2、MFC应用程序调用ACE库,不进行任何操作还存在内存泄露的问题;
3、MFC程序加载的动态链接库隐含调用ACE方法导致的内存泄露;
4、解决宽字符集和窄字符集的编译器自动兼容问题;
下面逐一解决:
1、解决Visual Studio 2008 编译5.6版本的ACE使用 ACE_HAS_MFC 后提示WIN32_WINNT版本过低的问题。
 原因在config-win32-common的这一句:
#if !defined (_WIN32_WINNT)
# define _WIN32_WINNT 0x0400
#endif
改为
#if !defined (_WIN32_WINNT)
# define _WIN32_WINNT 0x0600
#endif
即可
2、MFC应用程序调用ACE库,不进行任何操作还存在内存泄露的问题;
    这种情况需要解决两个问题:
    首先是由于ACE的Object_Manager的工作方式造成不以main()入口的进程无法自动初始化和清理。在以main()函数为入口的程序(控制台之类),或者使用了宽字符的_w_main入口的程序中,ACE库会自动在入口处调用 ACE::init()完成对象的初始化,在结束时调用ACE::fini()进行对象清理。而MFC程序和以WinMain入口的程序,ACE不会自己调用。因此,需要手工添加。重载CWinApp的InitInstance()和ExitInstance(),在所有步骤开始前初始化ACE,在所有工作结束后终止ACE,范例:
BOOL CMyApp::InitInstance()
{
 ...
 CWinApp::InitInstance();
 ...
 ACE::init();
 ....
}
int CMyApp::ExitInstance()
{
 ACE::fini();
 return CWinApp::ExitInstance();
}
    如果在Dll中,不要试图在DllMain之类的入口进行初始化,会导致内存泄露。在Dll中导出两个方法,一个用于初始化,一个用于终止,分别调用ACE::init();ACE::fini();就可以。范例:
int MY_EXT_DLL MY_init(void)
{
 ...
 return ACE::init();
}
int MY_EXT_DLL MY_fini(void)
{
 ...
 return ACE::fini();
}
主程序:
BOOL CMyApp::InitInstance()
{
 ...
 CWinApp::InitInstance();
 ...
 MY_init();
 ....
}
int CMyApp::ExitInstance()
{
 MY_fini();
 return CWinApp::ExitInstance();
}
    其次,ACE编译的时候,默认的config.h中没有定义ACE_HAS_MFC,导致ACE的线程并不是派生自MFC的CWinThread,于是在程序结束时维护线程的额外信息无法清理。这需要在编译ACE时指名MFC选项。
#ifndef ACE_HAS_MFC
#define ACE_HAS_MFC 1
#endif
    这种做法有缺点。这样做后,编译出的ACEDLL将需要MFC库,更要命的是,如果打算在DLL中使用,必须创建基于MFC的DLL。一般的适用案例:
 MFCApp->ACE(MFC)
 MFCApp->MFCDLL->ACE(MFC)
    不过解决了这两个问题,一般就能解决MFC程序中的内存泄露了!
3、MFC程序加载的动态链接库隐含调用ACE方法导致的内存泄露;
    首先,如果加载ACE的动态链接库是标准WindowsDll,而使用该Dll的是MFC程序,MFCApp->Win32Dll->ACE(Win32),就比较麻烦。一般这种应用方式带来的是一次性的内存泄露,不影响工作。只是让人很不爽罢了。如果还允许修改工程结构,则把调用过程改做:MFCApp->MFCDLL->ACE(MFC),其他步骤就如第一个问题中所述。
4、解决宽字符集和窄字符集的兼容问题;
    自从Visual Studio 2005后,编译器默认字符集就是宽字符。包括CString在内的多数对象均采用Unicode字符集。一般为了在宽字符集和窄字符集中切换,程序员会使用一系列的模版方法,比如_tcscpy()与TCHAR混用来克服一致性的问题,使得在编译时切换字符集不必重写代码。
    如果没有在ACE编译时指定ACE_USES_WCHAR,ACE所有函数入口都是窄字符的,将增加编程的复杂性。比如,我定义了一个ACE内存映射对象,需要初始化当前文件的名字,为了兼容Unicode字符集和窄字符可能这样写:
class CMyClass
{
 ...
 ACE_Mem_Map m_memmap;
 ...
}
void CMyClass::MyFun1()
{
 CString strDiskFileName(_T("NoName"));
 //获取文件名
 CFileDialog filedlg(FALSE,_T(".map"),0,4|2,_T("映像文件(*.map)|*.map|所有文件(*.*)|*.*|"));
 if (filedlg.DoModal()==IDCANCEL)
  return;
 strDiskFileName = filedlg.GetPathName();
 //打开文件
#ifdef _UNICODE
--> if (m_memmap.map(CW2A(strDiskFileName),nSize,O_RDWR | O_CREAT)==-1)
 {
  if (m_memmap.map(nSize)==-1)
   return NULL;
 }
#else
--> if (m_memmap.map(strDiskFileName,nSize,O_RDWR | O_CREAT)==-1)
 {
  if (m_memmap.map(nSize)==-1)
   return NULL;
 }
#endif
 ...
}
    这段代码使用了MFC的CW2A类,如果程序中多次出现类似CW2A的转换,当突然需要改为窄字符时,就需要大改代码。何况,Win32API没有提供CW2A类,取而代之的是系统方法调用。还接着上一个例子,如果想在非MFCDLL中取得页面文件的名字并保存,代码变得十分可怕:
class CMyClass
{
 ...
 ACE_Mem_Map m_memmap;
 TCHAR m_strFileName[BUFLEN];
 ...
}
void CMyClass::MyFun2()
{
 const char * pcstrFileName = m_memmap.filename();
#ifdef _UNICODE 
 //转换窄字符为宽字符,没有MFC只能调用API
 size_t origsize = strlen(pcstrFileName) + 1;
 size_t convertedChars = 0;
 if (0==::MultiByteToWideChar(CP_THREAD_ACP,MB_PRECOMPOSED,pcstrFileName,origsize+1,m_strFileName,BUFLEN))
 {
  MessageBoxA(0,"代码页错误!","Error",MB_OK);
  return ;
 }
#else
 _tcscpy(m_strFileName,pcstrFileName);
#endif
 ...
}
为了避免这种麻烦,采用如下手段:
    首先,修改工程文件,除了Debug和Release外创建UnicodeDebug,UnicodeRelease编译方案,为他们设置"Use Unicode Character Set"字符集选项;输出文件为UnicodeRelease:ACEu.dll,ACEu.lib,UnicodeDebug:ACEud.dll,ACEud.lib,存放到固定的文件夹中。
    而后,重写config.h,基本如下:
#ifdef _UNICODE
#ifndef ACE_USES_WCHAR
#define ACE_USES_WCHAR
#endif
#endif
#ifndef ACE_HAS_MFC
#define ACE_HAS_MFC 1
#endif
#include "ace/config-win32.h"
    重新编译,将编译生成四组库,ACE/ACEd/ACEu/ACEud,可以同样修改QoS及其他工程。注意,Qos链接选项中的ACEdll要配合字符集选项设置。接着,创建$(ACEDIR)/ACEPreInclude.h,如下:
//本文件提供对ACE的智能引用,链接对应的库
#ifdef _UNICODE
#define ACE_USES_WCHAR
 #ifdef _DEBUG
  #pragma comment( lib, "aceud.lib")
 #else
  #pragma comment( lib, "aceu.lib")
 #endif
#else
 #ifdef _DEBUG
  #pragma comment( lib, "aced.lib")
 #else
  #pragma comment( lib, "ace.lib")
 #endif
#endif
    最后,在要使用ACE库的项目中,Stdafx.h加入:
    #include "ACEPreInclude.h"
    即可。编译器将自动根据字符集选项选择相应的库进行连接。写好后,上述范例代码变为:
class CMyClass
{
 ...
 ACE_Mem_Map m_memmap;
 ACE_TCHAR m_strFileName[BUFLEN];
 ...
}
void CMyClass::MyFun2()
{
 const ACE_TCHAR * pcstrFileName = m_memmap.filename();
 _tcscpy(m_strFileName,pcstrFileName);
}
简单多了哦!
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/75914/showart_1901727.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP