Hui 的个人资料逆风沉沦日志列表 工具 帮助

日志


2007/1/8

怎么由dll文件生成对应的lib文件

我有一个DLL及对应的头文件,如何生成VC所要的LIB文件。 
 
1. dumpibn   /exports   Your.dll   >   Your.def  
  edit   Your.def,Let   it   become   standard   def   file  
  (  
  like:  
   
  EXPORTS:  
    abc  
    def  
   
  )  
   
  lib   /def:Your.def   /out:Your.lib  
 

2. 有了头文件,说明你已经知道导出函数。  
  可以这样:使用楼上兄弟提到的工具查到对应函数导出函数写一个DEF文件:  
  LIBRARY   youdll.dll  
  EXPORTS  
          Func1@0                             @2  
   
  然后  
  lib   /MACHINE:IX86   /DEF:yourLIB.DEF  
2007/1/5

高效拆分字符串

 

inline int stringSplit1(const char* lpszToSplit,char delemit, const char* lpszStartArray[],int nSizeArray[],int nArraySize)
{
        if(!lpszToSplit)
                return 0;
        int             nPart   = 0;   
        int             nSize   = 0;
        bool    bNew    = true;
        for(;*lpszToSplit;lpszToSplit++)
        {      
                if(bNew)
                {              
                        nPart++;
                        if(nPart > nArraySize)
                                break;
                       
                        bNew = false;
                        lpszStartArray[nPart-1] = lpszToSplit;
                        nSize = 0;
                }
               
                if(*lpszToSplit==delemit)
                {      
                        bNew =true;            
                        nSizeArray[nPart-1] = nSize;
                }
                else
                {
                        nSize++;
                }
        }
        if(!bNew)
                nSizeArray[nPart-1] = nSize;
        return nPart > nArraySize ? -1 : nPart ;
}
2006/12/19

写了一个分割字符串的函数

void stringSplit(const std::string& strToSplit,const std::string& strDelimit, std::vector<std::string>& vecStringOutput)
{
        vecStringOutput.clear();
        std::string::size_type begin,end;
        begin = strToSplit.find_first_not_of(strDelimit);
        while(begin!=std::string::npos)
        {
                end = strToSplit.find_first_of(strDelimit,begin);
                vecStringOutput.push_back(strToSplit.substr(begin,end-begin));
                begin = strToSplit.find_first_not_of(strDelimit,end);
        }
}
 
void stringSplit(const std::string& strToSplit,char delimit, std::vector<std::string>& vecStringOutput)
{
        vecStringOutput.clear();
        std::string::size_type begin=0,end=0,length=strToSplit.length();
        while(begin<length && end!=std::string::npos)
        {
                end = strToSplit.find(delimit,begin);
                vecStringOutput.push_back(strToSplit.substr(begin,end-begin));
                begin = end + 1;
        }
}
2006/11/24

ifstream, ofstream 有时打开带中文路径的文件会失败

似乎跟文件系统是ntfs还是fat有关, 解决的办法如下:
 
1. 使用c函数
setlocale(LC_ALL,"Chinese-simplified");
 
2. 使用stl
std::locale::global(std::locale(""));
 
2006/9/26

CHyperLink动态创建时存在问题

CHyperLink动态创建时存在问题
 CHyperLink是网上流传很广的一个超链接类, 但是我在使用过程中发现, 动态创建该类时会出现问题, 经跟踪调试发现问题出在CHyperLink类的PreSubclassWindow中. 先看看代码:

void CHyperLink::PreSubclassWindow()
{     
 // If the URL string is empty try to set it to the window text
    if (m_strURL.IsEmpty())
        GetWindowText(m_strURL);

    // Check that the window text isn't empty.
 // If it is, set it as URL string.
    CString strWndText;
    GetWindowText(strWndText);
    if (strWndText.IsEmpty()) {
  // Set the URL string as the window text
        ASSERT(!m_strURL.IsEmpty());    // window text and URL both NULL!
  CStatic::SetWindowText(m_strURL);
    }

    // Get the current window font 
    CFont* pFont = GetFont(); 
 
 if (pFont != NULL) {
  LOGFONT lf;
  pFont->GetLogFont(&lf);
  lf.lfUnderline = BITSET(m_dwStyle, StyleUnderline);
  if (m_Font.CreateFontIndirect(&lf))
   CStatic::SetFont(&m_Font);   
  // Adjust window size to fit URL if necessary
  AdjustWindow();
 }
 else {  
  // if GetFont() returns NULL then probably the static
  // control is not of a text type: it's better to set
  // auto-resizing off
  CLEARBITS(m_dwStyle,StyleAutoSize);
 }
 
 if (!BITSET(m_dwStyle,StyleNoHandCursor))
  SetDefaultCursor();      // Try to load an "hand" cursor

    // Create the tooltip
    CRect rect;
    GetClientRect(rect);
    m_ToolTip.Create(this); 

    m_ToolTip.AddTool(this, m_strURL, rect, TOOLTIP_ID);

    CStatic::PreSubclassWindow();
}

通常我们动态创建该类都是这样写的:
CHyperLink *pHyperLink = new CHyperLink;
pHyperLink->Create("hello",WS_CHILD|WS_VISIBLE,CRect(0,0,100,100),this);

很少有人会在调用Create之前先调用SetURL, 这样 ASSERT(!m_strURL.IsEmpty())这句会断言失败, 为了避免这种情况, 必须记得在Create之前先调用SetURL, 给m_strURL赋上值, 或者将这里改为:
if(!m_strURL.IsEmpty())
    CStatic::SetWindowText(m_strURL);

另一个严重的问题是m_ToolTip.Create(this)会引起崩溃, 解决的方法是将以下几句
    CRect rect;
    GetClientRect(rect);
    m_ToolTip.Create(this); 
    m_ToolTip.AddTool(this, m_strURL, rect, TOOLTIP_ID);
移动到OnCreate中去.

CHyperLink类见如下链接:
http://www.codeguru.com/Cpp/controls/controls/hyperlinkcontrols/article.php/c2185#more

2006/6/13

c++:在类的构造函数中调用另一个构造函数

c++:在类的构造函数中调用另一个构造函数

    在java里,经常可见类的构造函数调用另一个构造函数,但是在c++里,由于构造函数允许有默认参数,使得这种需求大为减少。虽然这样,也许偶尔我们还是希望在类的构造函数里调用另一个构造函数。我们知道,构造一个对象时会做两件事:1,分配内存 2,执行构造函数;所以在构造函数里调用另一个构造函数的关键是让第二个构造函数在第一次分配好的内存上执行,而不是分配新的内存,这个可以用标准库的placement new做到:

    先看看标准库中placement new的定义
    inline void *__cdecl operator new(size_t, void *_P)
        {return (_P); }

    可见没有分配新的内存。
 
   
#include <new>

class my
{
public:
        my()
        {
                new (this) my(5);
        }

        my(int i)
        {
                a=i;
        }

        int a;
};

    使用这个方法需要注意,如果第一个构造函数里初始化了某个成员变量,然后调用另一个构造函数,在这个构造函数里又初始化了同一个成员变量,这样就会造成同一个成员变量初始化了两次。但这种问题在java中也存在,编程时注意一下顺序就好了。

2006/6/8

CDialog窗口类的Class Style中没有CS_VREDRAW和CS_HREDRAW导致自绘有问题

CDialog窗口类的Class Style中默认没有CS_VREDRAW和CS_HREDRAW导致自绘有问题
 
    最近为了美化程序,需要在CDialog的派生类中自绘一些东西,其中最简单的自绘是在对话框客户区边沿画一些线条(在OnPaint中绘图),但是这种最简单的自绘也会产生问题,我的对话框是能改变大小的,当改变对话框大小的时候,总会残留改变大小之前的绘图,用Spy++查看对话框的Class Style,发现对话框在默认状态下的Class Style是CS_SAVEBITS和CS_DBLCLKS,并没有CS_VREDRAW和CS_HREDRAW,这样当对话框大小改变的时候,只有新增加的区域得到了重绘,而原来的区域保留了上次自绘时的状态,所以产生了残留,在OnInitDialog中调用
 
SetClassLong(m_hWnd,GCL_STYLE,CS_VREDRAW|CS_HREDRAW|CS_DBLCLKS);
 
人为的加上CS_VREDRAW|CS_HREDRAW属性,影像残留得到了解决。

    看来MFC对CDialog的绘图做了一些优化,可能是因为CDialog的背景比较简单,直接在Dialog上绘图的也比较少见吧。但是这种优化对在Dialog里自绘造成了一些麻烦。
  
 
2006/6/6

让对话框背景透明

在OnCtlColor里返回一个空的HBRUSH即可:
    hbr = (HBRUSH)::GetStockObject(NULL_BRUSH);
2006/3/7

旧话重提:pImpl惯用手法的背后(转载)

旧话重提:pImpl惯用手法的背后
                                                  刘未鹏
 
    pImpl惯用手法已经太老了,老得人们已经记不得它是什么时候被提出的了。像这么一个老得牙都掉了的东东几乎是肯定讲不出什么新意出来的。本文也不例外,只不过,这里我们并不想提出什么新的创意,而是对pImpl背后的机制作一个探究和总结。
城门失火 殃及池鱼
    pImpl惯用手法的运用方式大家都很清楚,其主要作用是解开类的使用接口和实现的耦合。如果不使用pImpl惯用手法,代码会像这样:
       //c.hpp
        #include<x.hpp>
class C
        {
        public:
            void f1();
        private:
            X x; //与X的强耦合
        };
像上面这样的代码,C与它的实现就是强耦合的,从语义上说,x成员数据是属于C的实现部分,不应该暴露给用户。从语言的本质上来说,在用户的代码中,每一次使用”new C”和”C c1”这样的语句,都会将X的大小硬编码到编译后的二进制代码段中(如果X有虚函数,则还不止这些)——这是因为,对于”new C”这样的语句,其实相当于operator new(sizeof(C) )后面再跟上C的构造函数,而”C c1”则是在当前栈上腾出sizeof(C)大小的空间,然后调用C的构造函数。因此,每次X类作了改动,使用c.hpp的源文件都必须重新编译一次,因为X的大小可能改变了。在一个大型的项目中,这种耦合可能会对build时间产生相当大的影响。pImpl惯用手法可以将这种耦合消除,使用pImpl惯用手法的代码像这样:
        //c.hpp
        class X;  //用前导声明取代include
        class C
        {
         ...
         private:
            X* pImpl; //声明一个X*的时候,class X不用完全定义
        };
    在一个既定平台上,任何指针的大小都是相同的。之所以分为X*,Y*这些各种各样的指针,主要是提供一个高层的抽象语义,即该指针到底指向的是那个类的对象,并且,也给编译器一个指示,从而能够正确的对用户进行的操作(如调用X的成员函数)决议并检查。但是,如果从运行期的角度来说,每种指针都只不过是个32位的长整型(如果在64位机器上则是64位,根据当前硬件而定)。正由于pImpl是个指针,所以这里X的二进制信息(sizeof(C)等)不会被耦合到C的使用接口上去,也就是说,当用户”new C”或”C c1”的时候,编译器生成的代码中不会掺杂X的任何信息,并且当用户使用C的时候,使用的是C的接口,也与X无关,从而X被这个指针彻底的与用户隔绝开来。只有C知道并能够操作pImpl成员指向的X对象。
 
防火墙
    “修改X的定义会导致所有使用C的源文件重新编译”这种事就好比“城门失火,殃及池鱼”,其原因是“护城河”离“城门”太近了(耦合)。pImpl惯用手法又被成为“编译期防火墙”,什么是“防火墙”,指针?不是。C++的编译模式为“分离式编译”,即不同的源文件是分开编译的。也就是说,不同的源文件之间有一道天然的防火墙,一个源文件“失火”并不会影响到另一个源文件。但是,这里我们考虑的是头文件,如果头文件“失火”又当如何呢?头文件是不能直接编译的,它包含于源文件中,并作为源文件的一部分被一起编译。这也就是说,如果源文件S.cpp使用了C.hpp,那么class C的(接口部分的)变动将无可避免的导致S.CPP的重新编译。但是作为class C的实现部分的class X却完全不应该导致S.cpp的重新编译。因此,我们需要把class X隔绝在C.hpp之外。这样,每个使用class C的源文件都与class X隔离开来(与class X不在同一个编译单元)。但是,既然class C使用了class X的对象来作为它的实现部分,就无可避免的要“依赖”于class X。只不过,这个“依赖”应该被描述为:“class C的实现部分依赖于class X”,而不应该是“class C的用户使用接口部分依赖于class X”。如果我们直接将X的对象写在class C的数据成员里面,则显而易见,使用class C的用户“看到”了不该“看到”的东西——class X——它们之间产生了耦合。然而,如果使用一个指向class X的指针,就可以将X的二进制信息“推”到class C的实现文件中去,在那里,我们#include”x.hpp”,定义所有的成员函数,并依赖于X的实现,这都无所谓,因为C的实现本来就依赖于X,重要的是:此时class X的改动只会导致class C的实现文件重新编译,而用户使用class C的源文件则安然无恙!
    指针在这里充当了一座桥。将依赖信息“推”到了另一个编译单元,与用户隔绝开来。而防火墙是C++编译器的固有属性。
 
穿越C++编译期防火墙
    是什么穿越了C++编译期防火墙?是指针!使用指针的源文件“知道”指针所指的是什么对象,但是不必直接“看到”那个对象——它可能在另一个编译单元,是指针穿越了编译期防火墙,连接到了那个对象。从某种意义上说,只要是代表地址的符号都能够穿越C++编译期防火墙,而代表结构(constructs)的符号则不能。
    例如函数名,它指的是函数代码的始地址,所以,函数能够声明在一个编译单元,但定义在另一个编译单元,编译器会负责将它们连接起来。用户只要得到函数的声明就可以使用它。而类则不同,类名代表的是一个语言结构,使用类,必须知道类的定义,否则无法生成二进制代码。变量的符号实质上也是地址,但是使用变量一般需要变量的定义,而使用extern修饰符则可以将变量的定义置于另一个编译单元中。
 
2006/2/13

创建一个无边框的CFrameWnd窗口

    我想在某个窗口内创建一个没有边框的CFrameWnd类型的子窗口, 数次试验均未能成功. 虽然我已经去除了WS_BORDER,WS_EX_CLIENTEDGE等属性,只留下WS_VISIBLE|WS_POPUP属性. 后来终于找到正确的创建方法:
   
    CFrameWnd *f=new CFrameWnd();
    f->Create(0,"NoBorder window(with border)",WS_VISIBLE|WS_POPUP,CRect(100,100,200,200));
    f->ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);  
   
    代码的关键是f->ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED), 我曾经使用过f->ModifyStyleEx(WS_EX_CLIENTEDGE, 0, 0), 然而产生出来的窗口仍然有边框, 令我大为不解, 而SWP_FRAMECHANGED参数的重要性在于, 这个标志会使SetWindowPos函数发送WM_NCCALCSIZE消息, 重新计算非客户区的尺寸.
   
参考:
    http://www.codeguru.com/forum/showthread.php?t=196014
2005/12/9

VC 编译选项大全 (转载)

Visual C++ Compiler Options  
 
 
 
-优化- 
/O1 最小化空间 minimize space
/Op[-] 改善浮点数一致性 improve floating-pt consistency
/O2 最大化速度 maximize speed
/Os  优选代码空间  favor code space
/Oa 假设没有别名 assume no aliasing
/Ot 优选代码速度 favor code speed
/Ob 内联展开(默认 n=0) inline expansion (default n=0)
/Ow  假设交叉函数别名  assume cross-function aliasing
/Od  禁用优化(默认值)  disable optimizations (default)
/Ox  最大化选项。(/Ogityb2 /Gs) maximum opts. (/Ogityb1 /Gs)
/Og  启用全局优化  enable global optimization 
/Oy[-]  启用框架指针省略  enable frame pointer omission
/Oi  启用内建函数  enable intrinsic functions

-代码生成- 
/G3  为 80386 进行优化  optimize for 80386
/G4  为 80486 进行优化  optimize for 80486
/GR[-]  启用 C++ RTTI  enable C++ RTTI
/G5  为 Pentium 进行优化  optimize for Pentium
/G6 为 Pentium Pro 进行优化  optimize for Pentium Pro
/GX[-]  启用 C++ 异常处理(与 /EHsc 相同)  enable C++ EH (same as /EHsc)
/EHs  启用同步 C++ 异常处理  enable synchronous C++ EH
/GD 为 Windows DLL 进行优化 optimize for Windows DLL
/GB  为混合模型进行优化(默认)  optimize for blended model (default)
/EHa  启用异步 C++ 异常处理  enable asynchronous C++ EH
/Gd  __cdecl 调用约定  __cdecl calling convention 
/EHc  extern“C”默认为 nothrow  extern "C" defaults to nothrow
/Gr  __fastcall 调用约定  __fastcall calling convention
/Gi[-] 启用增量编译 enable incremental compilation
/Gz  __stdcall 调用约定  __stdcall calling convention 
/Gm[-]  启用最小重新生成  enable minimal rebuild
/GA  为 Windows 应用程序进行优化 optimize for Windows Application
/Gf  启用字符串池  enable string pooling 
/QIfdiv[-]  启用 Pentium FDIV 修复  enable Pentium FDIV fix 
/GF  启用只读字符串池  enable read-only string pooling 
/QI0f[-]  启用 Pentium 0x0f 修复  enable Pentium 0x0f fix
/Gy  分隔链接器函数  separate functions for linker
/GZ  启用运行时调试检查 enable runtime debug checks
/Gh 启用钩子函数调用 enable hook function call
/Ge  对所有函数强制堆栈检查  force stack checking for all funcs
/Gs[num]  禁用堆栈检查调用  disable stack checking calls

-输出文件- 
/Fa[file]  命名程序集列表文件  name assembly listing file
/Fo  命名对象文件  name object file
/FA[sc]  配置程序集列表  configure assembly listing 
/Fp  命名预编译头文件  name precompiled header file
/Fd[file]  命名 .PDB 文件  name .PDB file 
/Fr[file]  命名源浏览器文件  name source browser file
/Fe  命名可执行文件  name executable file
/FR[file]  命名扩展 .SBR 文件  name extended .SBR file
/Fm[file]  命名映射文件  name map file

-预处理器- 
/FI  命名强制包含文件  name forced include file
/C  不吸取注释  don't strip comments 
/U  移除预定义宏  remove predefined macro
/D{=|#}  定义宏  define macro
/u  移除所有预定义宏  remove all predefined macros
/E  将预处理定向到标准输出 preprocess to stdout
/I 添加到包含文件的搜索路径  add to include search path
/EP  将预处理定向到标准输出,不要带行号  preprocess to stdout, no #line
/X  忽略“标准位置”  ignore "standard places"
/P  预处理到文件  preprocess to file

-语言- 
/Zi  启用调试信息  enable debugging information
/Zl  忽略 .OBJ 中的默认库名  omit default library name in .OBJ
/ZI  启用调试信息的“编辑并继续”功能 enable Edit and Continue debug info
/Zg  生成函数原型  generate function prototypes
/Z7  启用旧式调试信息  enable old-style debug info
/Zs  只进行语法检查  syntax check only
/Zd  仅要行号调试信息  line number debugging info only
/vd{0|1}  禁用/启用 vtordisp  disable/enable vtordisp
/Zp[n]  在 n 字节边界上包装结构  pack structs on n-byte boundary
/vm  指向成员的指针类型  type of pointers to members
/Za  禁用扩展(暗指 /Op)  disable extensions (implies /Op)
/noBool  禁用“bool”关键字  disable "bool" keyword
/Ze  启用扩展(默认)  enable extensions (default)

- 杂项 - 
/?, /help  打印此帮助消息  print this help message
/c  只编译,不链接  compile only, no link
/W  设置警告等级(默认 n=1)  set warning level (default n=1)
/H  最大化外部名称长度  max external name length
/J  默认 char 类型是 unsigned  default char type is unsigned
/nologo  取消显示版权消息  suppress copyright message
/WX  将警告视为错误  treat warnings as errors
/Tc  将文件编译为 .c  compile file as .c 
/Yc[file]  创建 .PCH 文件  create .PCH file
/Tp  将文件编译为 .cpp  compile file as .cpp 
/Yd  将调试信息放在每个 .OBJ 中  put debug info in every .OBJ
/TC  将所有文件编译为 .c  compile all files as .c 
/TP  将所有文件编译为 .cpp  compile all files as .cpp 
/Yu[file]  使用 .PCH 文件  use .PCH file
/V  设置版本字符串  set version string
/YX[file]  自动的 .PCH 文件 automatic .PCH
/w  禁用所有警告  disable all warnings
/Zm  最大内存分配(默认为 %)  max memory alloc (% of default)

-链接- 
/MD  与 MSVCRT.LIB 链接  link with MSVCRT.LIB
/MDd  与 MSVCRTD.LIB 调试库链接  link with MSVCRTD.LIB debug lib
/ML  与 LIBC.LIB 链接  link with LIBC.LIB
/MLd  与 LIBCD.LIB 调试库链接  link with LIBCD.LIB debug lib
/MT  与 LIBCMT.LIB 链接  link with LIBCMT.LIB 
/MTd  与 LIBCMTD.LIB 调试库链接  link with LIBCMTD.LIB debug lib
/LD  创建 .DLL  Create .DLL 
/F  设置堆栈大小  set stack size
/LDd  创建 .DLL 调试库  Create .DLL debug libary
/link  [链接器选项和库]  [linker options and libraries]

_set_se_translator 在RELEASE 模式下不起作用

Use /EHa instead of /EHsc when using _set_se_translator.
 
2005/12/2

编译ATL工程出现错误:LNK2001: unresolved external symbol _main (转载)

问题: 
    我创建了一个ATL工程,加入了一些代码,编译时得到如下错误信息:
    Linking... 
      Creating library ReleaseMinSize/mail.lib and object ReleaseMinSize/mail.exp
    LIBCMT.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
    不知是何原因,请指教!
 
回答:
    你肯定在程序中使用了一些标准的C语言函数,如mem*函数。如果你想知道到底是哪个函数,可以在工程设置的ignore libraries中输入Libcmt.lib。再次链接时,会报告一些函数找不到,你就可以知道是哪些函数了。如果这些函数是必须的,解决的办法就是从工程设置中删除_ATL_MIN_CRT。
 
2005/11/18

控制WebBrowser的下载行为

控制WebBrowser的下载行为
    在内嵌WebBrowser的程序中, 通常有控制下载内容的需要, WebBrowser控件是通过一个 DISPID_AMBIENT_DLCONTROL 的周边属性值来进行下载内容控制的. 在VC里一般我们都是通过继承CHtmlView来实现我们的程序,这样只要实现CWnd类的虚拟函数BOOL OnAmbientProperty(COleControlSite* pSite, DISPID dispid, VARIANT* pvar) 即可,具体实现如下:

BOOL CMyInternetExplorer::OnAmbientProperty(COleControlSite* pSite, DISPID dispid, VARIANT* pvar)
{
    if (dispid == DISPID_AMBIENT_DLCONTROL)
    {
        DWORD dwFlag=0;    
        dwFlag |= DLCTL_DLIMAGES ;
        dwFlag |= DLCTL_VIDEOS ;
        dwFlag |= DLCTL_BGSOUNDS ;
       
        pvar->vt = VT_I4;
        pvar->lVal = dwFlag;
        return TRUE;
    }
    return CHtmlView::OnAmbientProperty(pSite, dispid, pvar);
}
   
    上述函数即控制程序要下载图片, 视频和声音. 其他控制选项可参看MSDN.
   
    值得注意的是IE本身并没有禁止播放flash的控制接口, 但是可以通过改变注册表值来控制是否播放flash, 将注册表键[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{D27CDB6E-AE6D-11cf-96B8-444553540000}]下项"Compatibility Flags"的值置为0表示播放flash, 置为1024表示不播放flash, 其中D27CDB6E-AE6D-11cf-96B8-444553540000是flash播放器的CLSID.
2005/11/15

在vc对话框中使用richedit

需要先调用AfxInitRichEdit()函数.
2005/11/7

使用_tcsncpy防止产生半个汉字

众所周知, VC中在MBCS编译选项下, strncpy和CString的Left等操作都可能产生汉字截断的现象, 实际上, 使用TCHAR中的_tcsncpy就可以防止半个汉字的产生, 在MBCS环境下, _tcsncpy会被映射到_mbsnbcpy, _mbsnbcpy可以保证不会截断汉字.
2005/9/23

编译log4cxx-0.9.7发生cannot open input file "and.obj"错误

编译log4cxx-0.9.7发生LINK : fatal error LNK1181: cannot open input file "and.obj"错误
 
今天想在一个测试工程里用log4cxx,让我想起刚接触log4cxx时遇到的一个问题。当时我在网站下载log4cxx后就开始用vc编译,结果老是出现LINK : fatal error LNK1181: cannot open input file "and.obj"错误,让人莫名其妙,上网找了一圈也没有结果,搞笑的是有个老外也在一个论坛提出了这个问题,但是没人解答。后来过了一段时间我再编译的时候却成功了。仔细研究了一下终于发现了原因,原来我第一次是把源文件放在桌面上编译的,而第二次是把源文件放在D盘后编译的,而桌面的路径是带空格的。事情终于弄清楚了--log4cxx-0.9.7的vc工程不支持有空格的路径。虽然windows本身处理有空格的路径是没有问题的,但还是有不少应用程序有些问题--我记得以前的JBuilder就是。看来没事还是最好不要使这种用含特殊字符的路径。