VC版的朋友们好,虽然一直用VC,但没有到这里来过太多,其实这儿真有好多高手,好多东西可以学,想提高自己的水平,这里是个好地方,以后就要多谢大家的帮助了.  我的问题是这样的.我在写一个基于图像内容检索的小程序,用了IBM的Qbic api(是一些挺老的源代码).为了方便使用,我把所需功能包装在两个类里面,然后放在一个win32 console程序中调试通过,可以实现基于命令行的查询.
  为了界面好一点,我用AppWizard生成了一个基于Dialog的MFC程序,然后先把其中一个类加入工程,之后就出来很多link error,因为都是同一类型,取一条看看:
LIBC.lib(crt0dat.obj) : error LNK2005: _exit already defined in msvcrtd.lib(MSVCRTD.dll).  是说这两个库发生冲突了,导致方法重定义,大概是混用发生的问题,我用了/NODEFAULTLIB:(/NOD)msvcrtd.lib之后这种error消失了,但又出现了一种奇怪的warning:LINK : warning LNK4049: locally defined symbol "_free" imported... 查MSDN,说程序既导入又导出了symbol,不懂...好在不影响运行,按下不表.

解决方案 »

  1.   

    根源深久的链接问题之解决过程: 很早以前,当我刚开始使用Qbic的时候,我是用Console程序,当时没有一点问题,因为Qbic的Demo就是基于Console的,但后来移植到MFC架构
    下面的时候,出现了奇奇怪怪的连接错误,具体描述可以看我的项目中的readme和我在CSDN上的问题.主要是运行库之间的冲突吧,想了一些办法
    忽略掉了引起冲突的库,并绕开了因为忽略而找不到实现的一些函数调用,可以使用了...   为了编程方便转移在VC 7下面,将查询类加入项目又出现链接问题 - 
    要么找到冲突的源头,隐蔽之,即不作太大改动,通过一些设置来解决这个问题;
    要么使用ShellExec调用已经生成的外部查询程序,但是数据共享有很大问题;
    我的思想是使用DLL,只提供几个简单的外部接口,看能不能绕开库的冲突,因为Dll和Exe类似,已经将所连接的库包好,原来我使用导出
        类的方法,但是在使用Dll的地方,还是需要头文件的,所以还是要链入引起冲突的库,如果不是导出类,而是导出函数呢?
    发现Dll还是绕不开那几个库,因为Dll并没有把那些库包在其中,还得连接进来的...又想了一个思路,在DLL中把查询类的功能全部包在
    类似于API的全局函数中,导出之后自己写好定义,就不用包含Qbic的那些头文件了,也许可以避免连接Qbic库? 另外按照在MFC应用程序里使用Qbic的设置,在新的程序中只会出现一个与CStringT有关的link error(当然了,连msvcrt.lib都忽略掉
    了),试着用 原来的方法,避免那些调用,以下是我找到的关于CStringT Class-StrTraitATL的连接:
    http://www.thecodeproject.com/buglist/linkererrors.asp
    http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B309801

    为什么VC6下面可以编译的程序到了VC 7就出了问题?看来这就是根源:VC 7与VC 6的区别...
    MFC defines CString as:  typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString;
    While ATL defines CString as (With _ATL_CSTRING_NO_CRT defined.): typedef CStringT< TCHAR, StrTraitATL< TCHAR > > CString;
    This difference in the StrTrait is where all the problems with LNK2019 and LNK1120 come from. 大不了我重新回到VC 6下面去编写程序,反正都可以Run起来!找个可以转化VC7 solution为VC6 dsw的工具先。到了VC 6下面,问题依
    旧!因为忽略掉了msvcrt.lib,造成其中定义的mbscmp()找不到实现体,我把NDK连接到原来编译已经通过的程序中,没有问题,那么就是
    程序中新引入的问题咯?我在QueryServerDlg中把可能与CString/ATL有关的typedef CMap<long, long, CString, CString> CMapLongToString;
    及其相关项去掉,果然可以通过了,原来是
    if (strNickname == strNicknameMap)出了问题:
    运算符"=="是重载的,请看下面定义
    _AFX_INLINE int CString::Compare(LPCTSTR lpsz) const
    { ASSERT(AfxIsValidString(lpsz)); return _tcscmp(m_pchData, lpsz); }    // MBCS/Unicode aware

    __inline int _tcscmp(_CPC _s1,_CPC _s2) {return _mbscmp((_CPUC)_s1,(_CPUC)_s2);}

    所以_mbscmp()的缺失造成了link error。想个办法用替代方法来进行判断,我用的是C函数strcmp().哈哈,解决了,看来不一定要回到VC 6下
    面编写程序了,用同样的办法应该可以在VC 7里面避免冲突的.QueryServer编译通过了,我在VC 6下面编译QueryClient,按照以前QueryApp的
    设置,没有任何问题.
    周三中午到了实验室,打开VC.NET,如法炮制,QueryServer果然通过编译了,但是QueryClient出现了类似的链接错误:QueryClient error LNK2019: 无法解析的外部符号 __imp___mbslwr ,该符号在函数 "public: static char * __cdecl 
    ATL::ChTraitsCRT<char>::StringLowercase(char *)" (?StringLowercase@?$ChTraitsCRT@D@ATL@@SAPADPAD@Z) 中被引用有了QueryServer的经验,我这次直接找和CString有关的项: 呵呵,第一项就让我找到了:
    F:\Documents and Settings\Administrator\My Documents\Visual Studio Projects\QbicQueryCS\QueryClient\QueryClientDoc.cpp(186): CString strWildCard( pstr );
    顺藤摸瓜找到了在同一个函数里的:
    CString filePath = finder.GetFileName(); if( IsImageGDIPLUSValid( m_strCurrentDirectory + _T("\\") + filePath ) )
    {
    filePath.MakeLower(); 
    m_vFileName.push_back( filePath );
    }这就是了,提示的连接错误是说StringLower中引用的mbslwr找不到实现,显然MakeLower()就是用了StringLower的,那么我只要找到替代方法
    就可以了,这下面就是我的改动,工作的非常好,究其根源还是msvcrt.lib的忽略和VC不同版本之间的抵牾:
    CString filePath = finder.GetFileName(); if( IsImageGDIPLUSValid( m_strCurrentDirectory + _T("\\") + filePath ) )
    {
    // 因为_mbslwr()缺失,所以隐藏会调用它的MakeLower(); 不影响程序功能的
    // 我用strlwr来做...
    //filePath.MakeLower(); 
    strlwr((LPSTR)(LPCSTR)filePath);
    m_vFileName.push_back( filePath );
    }