在 Visual Studio 2008 MFC 工程中,利用 Berkeley DB 来构建数据存储引擎时,在编译 db.h 文件时出现编译错误,错误提示内容如下:
错误 3 error C2143: 语法错误 : 缺少"}"(在"("的前面) e:\water\berkeleydb\include\db.h 1226
微软的 MSDN 上有对 error C2143 的编译器错误进行解释,不过基本上没有太多可读性、可借鉴性,大意应该是一些宏定义、命名出错等。
最后,还是通过万能的 Google 大神找到了解答方法。错误的原因是 DB_TYPE, DB_UNKNOWN 类型已经在 MFC 系统头文件中被定义过,解决办法之一是在 db.h 中定义 DB_TYPE, DB_UNKNOWN 的语句之前加上如下语句即可:
#ifdef DB_UNKNOWN #undef DB_UNKNOWN #endif #ifdef DBTYPE #undef DBTYPE #else #define DBTYPE BDBTYPE #endif
看来,C 和 C++ 混在一块,命名、类型定义真是一个大问题。以后碰到类似的问题,也可以采用类似的解决办法。
参考资料:
今天为这件事情折腾了一天!
我用 Java 写的中间件,会根据用户的需要,启动一个子进程,这个进程是用 C++ 写的,正好用到了 Log4Cxx 来记录日志以便分析。这个进程,单独从控制终端运行,没有任何问题;但是一旦用 Java 启动子进程的方式来启动,则这个子进程刚一启动就阻塞不动了,然后大概等上几十分钟到两个小时不等,该子进程则又能顺利执行下去。
第一次碰到这样的问题,很怪异,经过反复测试及万能的 Google 帮忙,找到Java调用外部程序挂起原因,Log4Cxx 原来是罪魁祸首,因为它重定向了大量的日志信息到控制台,由于 Java 进程没有清空程序写到缓冲区的内容,结果导致程序一直在等待。
解决这个问题有两个办法:
问题搞定了,世界又变得很美好了!
在写客户端的时候,经常要传输一些文件,有一些服务器就是用 FTP 来搭建的,这个时候,如何用客户端来发起 FTP 网络连接呢?
如果是用 MFC 来发起 FTP 文件传输请求,和使用 MFC 来发起 HTTP 请求类似,非常简单。理论基础可以仔细阅读 MSDN 上的官方文档 Steps in a Typical FTP Client Application,浏忙绪绪在这里,就贴上我自己写的代码,与大家分享一下。
样例代码如下:
/* * 通过 ftp 方式来拿文件 * @param relativePath, 服务器保存该视频摘要文件夹、相对于 ftp 跟路径的相对路径 * @notice relativePath 应该是类似于 /test 这样相对于 ftp 根路径的相对路径 * 应该以 / 开头 * @param savePath, 从远程服务器下载文件后,在本地保存的文件夹路径 */ BOOL CGetRemoteFile::GetFtpfiles(CString relativePath, CString savePath) { //通过 http GET 协议来获取并保存文件 CString remotefile = L""; CString saveFilename = L""; CInternetSession session; session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 1000 * 20); session.SetOption(INTERNET_OPTION_CONNECT_BACKOFF, 1000); session.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 1); /* 替换成相应的 FTP 用户名和密码 */ CFtpConnection* pFtp = session.GetFtpConnection( m_strServerIP, m_strUsername, m_strPassword, (INTERNET_PORT)m_iSeverPort); bool result = pFtp->SetCurrentDirectory(relativePath); if (!result) { AfxMessageBox(L"Can't get ftp file"); return false; } CFtpFileFind finder(pFtp); BOOL bFind = finder.FindFile( L"*", INTERNET_FLAG_RELOAD ); while (bFind) { bFind = finder.FindNextFile(); CString strPath = (LPCTSTR)finder.GetFileURL(); CString strFile = (LPCTSTR)finder.GetFileName(); CString ftpPath; ftpPath.Format(L"正在下载文件:%s/%s\n", strPath, strFile); TRACE(ftpPath); CInternetFile* pFile = pFtp->OpenFile(strFile);//注意,这里只需要传文件名 int len = pFile->GetLength(); char buf[2000]; int numread; CString filepath; filepath.Format(L"%s\\%s", savePath, strFile); TRACE(L"保存为文件%s",filepath); CFile myfile( filepath, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary); while ((numread = pFile->Read(buf,sizeof(buf))) > 0) { strFile += buf; myfile.Write(buf, numread); } myfile.Close(); pFile->Close(); delete pFile; } session.Close(); return true; }
Emgu CV 是 OpenCV 跨平台的 C# 封装包,主要是为了方便在 C# 里使用 OpenCV 的库函数,下载和安装都很简单,新建一个 C# 控制窗口程序后,Hello World 例子代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using Emgu.CV; using Emgu.Util; using Emgu.CV.Structure; namespace OpenCVTester { class Program { static void Main(string[] args) { //The name of the window String win1 = "Test Window"; //Create the window using the specific name CvInvoke.cvNamedWindow(win1); //Create an image of 400x200 of Blue color using (Image<Bgr, Byte> img = new Image<Bgr, byte>(400, 200, new Bgr(255, 0, 0))) { //Create the font MCvFont f = new MCvFont(Emgu.CV.CvEnum.FONT.CV_FONT_HERSHEY_COMPLEX, 1.0, 1.0); //Draw "Hello, world." on the image using the specific font img.Draw("Hello, world", ref f, new Point(10, 80), new Bgr(0, 255, 0)); //Show the image CvInvoke.cvShowImage(win1, img.Ptr); //Wait for the key pressing event CvInvoke.cvWaitKey(0); //Destory the window CvInvoke.cvDestroyWindow(win1); } } } }
这里需要注意的是,如果用 Visual Studio 2008 来调试上面的代码,则记得要把 OpenCV 相关的动态链接库放到你测试工程的这个目录里:
\bin\Debug
否则在跑到下面这句代码
CvInvoke.cvNamedWindow(win1);
的时候,就会弹出一个莫名其妙的出错框,提示如下错误:
未处理的"System.TypeInitializationException"类型的异常出现在 OpenCVTester.exe 中。 其他信息: "Emgu.CV.CvInvoke"的类型初始值设定项引发异常
看来,C#调试时的程序动态链接库读取位置,还比较特殊呀~~
最近使用 OpenCV2.1 来生成视频,在 Windows 下碰到这样的问题:不管我用什么样的编码,都没有办法直接生成视频,并且会导致程序崩溃。代码如下:
_writer = cvCreateVideoWriter( video.c_str(),
CV_FOURCC('X','V','I','D'),
_fps,
cvSize(frameW,frameH),
isColor );
但是,如果我把编码换上 -1 选项来手工选取视频格式,则能顺利生成视频。代码如下:
_writer = cvCreateVideoWriter( video.c_str(),
-1,
_fps,
cvSize(frameW,frameH),
isColor );
这个应该是 OpenCV2.1 里的一个 Bug,换成 OpenCV2.2 就没有这个问题了。
官方的 OpenCV2.2 是在 Visual Studio 2010 下编译的二进制包,所以,当你把 OpenCV2.2 嵌入到 Visual Studio 2008 里,可以正常编译相关的代码,但是一运行,一定会提示找不到动态链接库 msvcp100d.dll 或是 msvcr100d.dll 。
这个时候,你可以把这两个 Visual Studio 2010 的动态链接库拷贝到编译好的可执行文件目录里。但是,最好的方式,是你在 Visual Studio 2008 里重新编译一下 OpenCV2.2。
有一些视频,我用 OpenCV 跳转到指定的时间,和用 DirectShow 跳转到视频指定的时间,理论上来说,应该是一样的。可是,在我这里,偏偏就出现了跳转视频位置不同的情况。而且,原始视频越长,这种误差越大。
是什么原因呢?
仔细研究了一下,我用 OpenCV 读取参数,会显示是 29 帧/秒,大约有 276168 帧;但是用 DirectShow 解码后显示为 30 帧/秒,计算后约为 268946 帧。
解码后的度量时间标准不同,也就导致了上述误差。但是,真实的原因是什么呢?
在 Linux 下,如果你写好了自己的动态链接库,需要在其它程序里调用,则需要让这些程序能找到这些动态链接库。如果设置不对,会出现类似如下的错误:
test: error while loading shared libraries: libexampleso.so.0: cannot open shared object file: No such file or directory
这是因为没有把动态链接库的安装路径(例如说是 /usr/local/lib )放到变量 LD_LIBRARY_PATH 里。
这时,可以用命令 export 来临时测试确认是不是这个问题:
export LD_LIBRARY_PATH=/usr/local/lib
在终端里运行上面这行命令,再运行这个可执行文件,如果运行正常就说明是这个问题。
接下来的问题是:以上做法,只是临时设置变量 LD_LIBRARY_PATH ,下次开机,一切设置将不复存在;如何把这个值持续写到 LD_LIBRARY_PATH 里呢?
我们可以在 ~/.bashrc 或者 ~/.bash_profile 中加入 export 语句,前者在每次登陆和每次打开 shell 都读取一次,后者只在登陆时读取一次。我的习惯是加到 ~/.bashrc 中,在该文件的未尾,可采用如下语句来使设置生效:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
修改完后,记得关掉当前终端并重新打开一个新的终端,从而使上面的配置生效。
我的笔记本电脑因为之前分区的原因,没有办法安装双系统,导致调试 Linux 程序诸多不便。如果你也有这种情况,或是有很多事情都需要同时在 Windows 和 Linux 下处理,可以和我一样,在本地装一个 VirtualBox 虚拟 Ubuntu 环境,配好相应的开发环境后,从事 Linux 代码的开发与调试工作。
把这个 VirtualBox 里的 Linux 当成服务器,用 putty 连上去,慢慢调试;本地文件,可以用 Eclipse 编辑好,通过文件共享或是 SCP 的方式,传到虚拟机里的 Linux 服务器里。
详细的 SSH 配置方法可以看一下在 Ubuntu 下开户 ssh 服务里的介绍。
可以用 WinSCP 同步 Windows 系统里的文件到 Ubuntu 里,当然,也可以采用 FTP 或是 SFTP 之类的软件来同步文件。
PS:如果你觉得用 WinSCP 来同步文件略显麻烦,你可以在 Windows 里设置一个供 Ubuntu 使用的共享目录,然后你直接把东西扔到这个目录,就可以在 Ubuntu 里访问相关的文件;当然,使用这种方法,你要小心保护好你的文件,不要轻易地删除共享目录里的文件。
出于模拟及方便的角度,我依然推荐使用 WinSCP 的方式来同步文件。
用 OpenCV 来读取视频,经常需要从指定帧序号的片断开始读取,这个时候,就需要用 cvSetCaptureProperty 结合参数 CV_CAP_PROP_POS_FRAMES 来设定,例子代码如下:
bool PickSomeFrames(const char* filename, int start, int end, char* savePath) { CvCapture* capture = cvCaptureFromAVI(filename); //读取视频文件 cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, start); int count = start; while( cvGrabFrame(capture) && count <= end ) { IplImage* pFrame = cvRetrieveFrame(capture);// 获取当前帧 char test[100]; sprintf(test,"%s\\%d%s",savePath,count,".jpg"); cvSaveImage(test,pFrame); count++; } cvReleaseCapture(&capture); return false; }
以上这种方法,支持用多线程的方式,来同时读写视频不同帧序号开始的片断。以上这些代码,在采用多线程来加速视频处理时,特别有用。
趁着今天有空,把 WordPress 维护了一把,不小心,碰到如下两个问题:
我准备在后台把 WordPress 从当前版本升级到 3.1.3,可是却出现了如下错误提示:
Fatal error: Call to undefined function wp_get_current_user() in /home1/cookwhyc/public_html/wp-includes/capabilities.php on line 1028
上 WordPress 官方论坛找了找几处说法,原因应该是一些插件还停留在旧版本的 WordPress 架构上,还会用旧方法调用 wp_get_current_user() 这类函数,引用一位人士的解释:
Esmi - the problem isn't that it isn't there. Its that current_user_can is being called by the plugin and for some reason although capabilities.php has been loaded (which contains the current_user_can function) that function calls wp_get_current_user which is defined in pluggable.php but hasn't been loaded when the call is made I think its actually a bug in WordPress - the solution is to add a require_once call to the top of capabilities.php.
解决办法可以在 /wp-includes/capabilities.php 文件正式代码的开头,添加下面这行语句:
require_once('pluggable.php');
希望以后的 WordPress 版本自动兼容这些问题。
在解决了上述问题后,我在控制面板点击升级到 3.1.3 这个链接,却又出现了错误页面,提示以下错误:
You do not have permission to access this page.
这个问题比较怪异,除了无法通过 Network Admin 部分来管理站点外,其它一切都正常,包括博客的前端页面及各个独立博客的管理面板。
即使我手动升级 WordPress 到了 3.1.3,依然没有办法解决这个没有权限访问的问题。
这个问题应该是由于插件不兼容新版本的 WordPress 造成的,手动删除了该插件即可解决此类问题。
想要手动删除某个插件,直接到下面这个目录删除该插件即可:
/wp-content/plugins
在我这里,是由插件 Ad Inserter 造成的。不知道为什么,Ad Inserter 在我的 3.1.3 版本 WordPress 里使用就会有这个问题。
经验总结:升级 WordPress 之前,一定要先把所有的插件都关闭,然后仔细地检查一下所有的插件是否兼容新版本的 WordPress,否则就很难找到具体是哪个插件出了问题。
最近被一个问题折磨了好几天,VC++2008 编译出来的 Debug 版本程序,拷到目标机器上,没有办法运行。我用 VC++2008 编译的文件在自己电脑上可以运行,可一放到别人电脑上就显示程序配置有问题,试了几台电脑都这样,拿到另一台装了 VC++2008 的电脑上又正常了。以前用 VC++6.0 的时候没这么多事,这是怎么回事呢?
类似这种情况下,按理说应该是少了某个动态链接库,但是我确定第三方的动态链接库都拷贝到目标机器上了。
在目标机器上安装 Microsoft Visual C++ 2008 Redistributable Package (x86) 后,程序依然不能运行。但是如果我装给目标机器装上 VS2008 ,程序就可以顺利执行。
这个问题和 Debug 版本有关吗?还是 VS2008 的问题?编译成 Release 版本能不能解决这个问题呢?
我用静态编译的方式,编译出的 release 版本就更奇怪了,在我自己的电脑上运行,都提示如下错误:
"无法启动程序,因为计算机中丢失 MSVCP90.dll。尝试重新安装该程序以解决此问题。
这个库我怎么可能会没有?
上 MSDN 仔细找了找原因,出现类似上面的问题,有以下几点需要注意:
在寻找答案的过程中,也在 StackOverflow 里提问获得了帮助,原文是 Where is msvcp90d.dll supposed to come from?,笔记一下以备查阅。
如果需要检测程序依赖的动态链接库有哪些,可以使用 Dependency Walker 这个工具。
PS: 看来 Stackoverflow 里,问题的回答质量是相当高的,以后可以尝试多用。