1、fatal error C1010: unexpected end of file while looking for precompiled header directive该如何解决?
如果发生错误的文件是由其他的C代码文件添加进入当前工程而引起的,则Alt+F7进入当前工程的Settings,选择C/C++选项卡,从Category组合框中选中Precompiled Headers,选择Not Using Precompiled headers。确定。
如果发生错误的文件原本是该工程中的,则检查该文件头部有没有#include "stdafx.h"语句,没有的话添加。
如果还不行,也有可能是定义的类或结构体等最后忘了加分号,注意一下。
2、fatal error RC1015: cannot open include file 'afxres.h'.该如何解决?
#include "afxres.h"语句是在.rc文件中的,而afxres.h文件在VC的安装目录中的./VC98/MFC/INCLUDE目录中,所以着重查一下Tools菜单中Options对话框中的Directories中的包括文件的路径是否正确,是否在VC的安装路径中,不是的话,改过来,如果这方面没问题,则到其他机器中拷贝afxres.h到相应的目录中。
3、Dll分配的内存块,应用程序释放,结果报异常。
用GlobalAlloc()代替new,用GlobalFree()代替delete就不会出错了。
其实还有一个办法,就是把dll的Settings的C/C++选项卡的Code Generation的Use Run-time liberary改成Debug Multithreaded DLL,在Release版本中改成Multithreaded DLL,就可以直接使用new和delete了,没问题。
比较规范点的做法一般是DLL分配的内存由DLL释放。在DLL中加一个函数释放内存不是更好吗。
4:发现打印预览的图形明显比屏幕显示图形小,怎么办?
这多半是CDC映射模式的选择引起的,缺省状态下,选择的是MM_TEXT模式,MM_TEXT以设备的像素点为单位,而不同设备的像素点的大小不同,打印机的分辨率比显示器要高很多,所以导致同样图形在打印时候变小。解决之道是统一使用其他定长的映射模式,比如MM_HIMETRIC等等(CDC::SetMapMode()改变映射模式)。
5、CString、char*、string、int、_bstr_t、CTime、COleDateTime等等的相互转换,如何判断一个字符串是一个浮点数?
#include<string>
using namespace std;
#include <COMDEF.H>
{
CString strCString="ABC";
char strchar[256],*pstr;
pstr=(LPSTR)(LPCTSTR)strCString; //CString---->char*
strcpy(strchar,(LPSTR)(LPCTSTR)strCString); //CString---->char[]
_bstr_t strbstr=pstr; //char*---->_bstr_t
WCHAR *strWCHAR=strbstr; //b_str_t--->UNICODE
strbstr=strWCHAR;
pstr=strbstr; //UNICODE---->char*
strCString="10";
int istr=atoi((LPSTR)(LPCTSTR)strCString); //CString、char[]、char*------>int
strCString.Format("%d",istr); //int----->CString
sprintf(strchar,"%d",istr); //int----->char[]
pstr=new char[256]; //字符串申请空间
strcpy(pstr,"ABC"); //字符串赋值
delete []pstr; //字符串释放
string strstring="ABC";
pstr=(char*)strstring.c_str(); //string---->char*
strCString="2003-10-27 6:24:37"; //CString--->COleDateTime
COleVariant vtime(strCString);
vtime.ChangeType(VT_DATE);
COleDateTime time4=vtime;
COleDateTime time1(1977,4,16,2,2,2); //COleDataTime--->CTime
SYSTEMTIME systime;
VariantTimeToSystemTime(time1, &systime);
CTime tm(systime);
time_t time2=tm.GetTime(); //CTime--->time_t
COleDateTime time3(time2); //time_t--->COleDateTime
//判断字符串是否是某种类型
CString sValue("123.1");
COleVariant vValue(sValue);
BOOL bStrIsFloat = (SUCCEEDED(VariantChangeType(&vValue, &vValue, 0, VT_R8)) && sValue.Find('.') != -1);
if(bStrIsFloat)
{
AfxMessageBox("浮点");
}
}
6、如何建立一个UNICODE应用程序?
建立一个应用程序,打开Alt+F7 settings选项,选择C/C++选项卡,在Preprocessor definenation中加上_UNICODE,在Link选项卡中,在Category选择框中选择Output,在Entry-point symbol编辑框中,添加wWinMainCRTStartup确定。
注意调试UNICODE程序时,需要在安装时VC选择所有选项,否则会缺少动态库和相应的.lib文件。
7、ADO操作数据库表,更新出现问题。
在打开数据库前,添加如下语句试一下pRecordSet->CursorLocation = adUseClient;
8、unknown software exception如何解决?
内存溢出。debug调试一下,程序出现一场时会自动进入断点,打开call stack调试窗口。会有相关出错函数和line提示。
9、刚开始的时候,为了把界面做得好看,我在www.codeproject.com和www.codeguru.com上面找到了一些好用的控件。如ButtonST、TruecolorToolbar、GradientProgressCtrl、CoolToolbar等控件。可能大家也用过。它们都很好用,而且有演示程序下载,边学边用,用对比法和增减法,这两个方法学MFC挺管用的。后来在www.vkbase.com看到了一个换肤的ActiveX控件,很好用。做出来的界面特好看。大家去下载看看。可惜对组合框等控件支持不够。(可能是小弟不会:))
后来做数据库的时候,我公司的高手说选择越简单的控件越好。我刚开始用DataGrid,直接绑定数据库。他们建议用原始的Grid控件,独立于具体的数据库。Grid控件没有(也不需要!)编辑和组合框支持。编辑的时候跳出对话框来解决。现在我做的一个项目的界面是单文档多个formview切换(这个界面挺古老的吧)。曾经用过属性页控件,现在用了Tab控件和对话框嵌入,感觉这个挺好的。
遇到控件问题的时候,我常看msdn,上面的实例真好。现在有问题来msdn,我都是先搜索一下,其实大多数问题都已经有帖子解答。这样可以节省自己和别人的时间。记住“每个控件都是一个窗口”是有帮助的。
10、多线程的时候尤其要注意一个问题:MFC帮我们开的线程是界面线程。如果我们以后再开的线程是工作者线程,那么界面主线程不能阻塞。如果界面主线程阻塞了,相当于消息泵阻塞了。我上次犯的错误就是让其他工作者线程发一个消息来让主线程解除阻塞,结果死锁。
解决方法是将其他线程改为界面线程。
还有一个问题,创建新线程的时候要小心,它有一个CRuntimeClass*的参数。它要CreateObject()创建一个新的线程,然后把线程指针返回。
CSerialPortEx* g_pPort = new CSerialPortEx;
CRuntimeClass* IOClass = g_pPort->GetRuntimeClass();
g_pPort = (CSerialPortEx*)AfxBeginThread(IOClass);
上面的代码将使g_pPort无法访问CSerialPortEx内部的变量。通过增加一个临时变量来解决。如下:
CSerialPortEx* TempPort = new CSerialPortEx;
CRuntimeClass* IOClass = TempPort->GetRuntimeClass();
g_pPort = (CSerialPortEx*)AfxBeginThread(IOClass);
delete TempPort;
类似的场合不少。如在用对话框嵌入标签的时候再一次创建了对话框。出现了实际上存在两个对话框,无法访问原来对话框上的控件。现在我一看到CRuntimeClass*就会特别小心。我在解决这些问题的时候用的方法是调试和增减法。并不是从书上得来。如果有差错,请各位指出来。呵呵。
还有一个问题是进度条对话框上的控件不能及时显示(消息循环暂时受阻塞),阿行大哥用在用户代码中加入消息循环解决。也可以开一个线程。
数据库我都没有怎么做过。我的项目不大。想请教各位设计的时候需要什么考虑,还有上面说的“使用简单的控件”是否合理。有没有必要自己写一个数据库类,用SQL语句进行访问。
11、数据结构我学得太烂了,现在非常后悔。不过只得加把劲了。幸亏我现在只用到链表和数组。呵呵。我觉得链表和数组都有欠缺。象我的项目,串口数据在不停地上来,根据上来的数据监控下面机器的状态。如果用数组,长度是固定的。如果用链表,有可能用户暂时不在监控界面(假设长达几个小时)。几个小时之内的数据用链表一直来存储着。然后等用户一切换回监控,就一下子从头到尾刷新?!如果什么都不用,直接用后一个状态覆盖前一个,那么就无法显示一系列的过程。正在考虑用一个固定长度的链表。
12、还有其他没考虑到的地方,大家提出来讨论吧。
VC做程序最重要的就是小心,小心再小心,每做一步自己都要多运行几遍,分别在debug,release模式下运行,看看有没有内存泄漏,越界等错误,等到最后才发现那就惨了。(1)程序运行稳定,尽量用老办法,不了解的函数不要随便用。(2)功能要简单实用。(3)不要追求功能的完美。完美的功能是不可能的。(4)程序一有bug,必须纠正后才能前进。
13、偶的一点经验之谈:
1)调试程序的时候由简单到复杂:碰到程序运行出错时,可以先把一些程序注释掉,只留很少的一部分,确保程序的正确运行,然后再逐段逐段代码的释放,很容易发现问题所在。
2)单独做试验:对程序中用到的一些独立的模块和功能,如果不是太熟悉或把握不准,可以单独写一个小的程序去做试验,验证用法以及结果。不要在很大的工程中调试某些独立的模块。
3)仔细认真地作试验。在研究一个新的控件或功能时,要象对待正式程序一样认真地对待,否则如果出现错误,你就有可能得出一个错误的结论,一旦用到整个的程序中就会是一个很难发现的错误,浪费大量的时间去查找其他的代码。
4)有时候错误的程序会莫名其妙地运行正常,但你并没有找到出错的原因。这时千万不要太高兴,应该继续调试和试验,一定要把错误找出来。只要你找不出来,这个错误就是一个炸弹,不一定什么时候发作。
5)进行数据库操作的时候,碰到比较复杂的SQL语句,最好先在数据库中执行测试你的SQL语句,以保证该语句的正确性。
6)建议在操作数据库的时候使用“事务处理”,否则程序在运行时(特别在网络中)会遇到意想不到的问题,如:网络不稳定可能会使你的操作只执行一部分。
7)长期连续运行的程序中,一些复杂的功能不要在定时器(OnTimer)中完成,而尽量使用线程完成,我的感觉是,放在线程中要比定时器稳定的多。(只是我自己的看法)
14、
AND_CATCHAND_CATCH
AND_CATCH(exception_class,exception _object_point_name)
说明:
定义一个代码块,它用于获取废除当前TRY块中的附加异常类型。使用CATCH宏以获得一个异常类型,然后使用AND_CATCH宏获得随后的异常处理代码可以访问异常对象(若合适的话)已得到关于异常的特别原因的更多消息。在AND_CATCH块中调用THROW_LAST宏以便把处理过程移到下个外部异常框架。AND_CATCH可标记CATCH或AND_CATCH块的末尾。
注释:
AND_CATCH块被定义成为一个C++作用域(由花括号来描述)。若用户在此作用域定义变量,那么记住他们只在此作用域中可以访问。他也用于exception_object_pointer_name变量。
ASSERT
ASSERT(booleanExpression)
说明:
计算变量的值。如果结构的值为0,那么此宏便打印一个诊断消息并且成讯运行失败。如果条件为非0,那么什么也不做。诊断消息的形式为:assertion failed in file in line ,其中name是元文件名,num是源文件中运行失败的中断号。在Release版中,ASSERT不计算表达式的值也就不中断程序。如果必须计算此表达式的值且不管环境如何那么用VERIFY代替ASSERT。
注释:
ASSERT只能在Debug版中用。
ASSERT_VAILD
ASSERT_VAILD(pObject)
说明:
用于检测关于对象的内部状态的有效性。ASSERT_VALID调用此对象的AssertValid成员函数(把它们作为自己的变量来传递)。在Release版中ASSERT_VALID什么也不做。在DEBUG版中,他检查指针,以不同于NULL的方式进行检查,并调用对象自己的AssertValid成员函数。如果这些检测中有任何一个失败的话,那么他会以与ASSERT相同的方法显示一个警告的消息。
注释:
此函数只在DEBUG版中有效。
BEGIN_MESSAGE_MAP
BEGIN_MESSAGE_MAP(the class,baseclass)
说明:
使用BEGIN_MESSAGE_MAP开始用户消息映射的定义。在定义用户类函数的工具(.cpp)文件中,以BEGIN_MESSAGE_MAP宏开始消息映射,然后为每个消息处理函数增加宏项,接着以END_MESSAGE_MAP宏完成消息映射。
CATCH
CATCH(exception_class,exception_object_pointer_name)
说明:
使用此用定义一个代码块,此代码用来获取当前TRY块中都一个异常类型。异常处理代码可以访问异常对象,如何合适的话,就会得到关于异常的特殊原因的更多消息。调用THROW_LAST宏以把处理过程一下一个外部异常框架,如果exception-class是类CExceptioon,那么会获取所有异常类型。用户可以使用CObject::IsKindOf成员函数以确定那个特别异常被排除。一种获取异常的最好方式是使用顺序的AND_CATCH语句,每个带一个不同的异常类型。此异常类型的指针由宏定义,用户不必定义。
注释:
此CATCH块被定义作一个C++范围(由花括号描述)。如用户在此范围定义变量,那么它们只在吃范围内可以访问。他还可以用于异常对象的指针名。
DEBUG_NEW
#define new DEBUG_NEW
说明:
帮助查找内存错误。用户在程序中使用DEBUG_NEW,用户通常使用new运算符来从堆上分配。在Debug模式下(但定义了一个DEBUG符号),DEBUG_NEW为它分配的每个对象记录文件名和行号。然后,在用户使用CMemoryState::DumpAllObjectSince成员函数时,每个以DEBUG_NEW分配的对象分配的地方显示出文件名和行号。 为了使用DEBUG_NEW,应在用户的资源文件中插入以下指令: #define new DEBUG_NEW 一旦用户插入本指令,预处理程序将在使用new的地方插入DEBUG_NEW,而MFC作其余的工作。但用户编译自己的程序的一个发行版时,DEBUG_NEW便进行简单的new操作,而且不产生文件名和行号消息。
DECLARE_DYNAMIC
DECLARE_DYNAMIC(class_name)
说明:
但从CObject派生一个类时,此宏增加关于一个对象类的访问运行时间功能。把DECLARE_DYNAMIC宏加入类的头文件中,然后在全部需要访问词类对象的.CPP文件中都包含此模块。如果像所描述那样使用DELCARE_DYNAMIC和IMPLEMENT_DYNAMIC宏,那么用户便可使用RUNTIME_CLASS宏和CObject::IsKindOf函数以在运行时间决定对象类。如果DECLARE_DYNAMIC包含在类定义中,那么IMPLEMETN_DYNAMIC必须包含在类工具中。
DECLARE_DYNCREATE
DECLARE_DYNCREATE(class_name)
说明:
使用DECLARE_DYNCRETE宏以便允许CObject派生类的对象在运行时刻自动建立。主机使用此功能自动建立新对象,例如,但它在串行化过程中从磁盘读一个对象时,文件及视图和框架窗应该支持动态建立,因为框架需要自动建立它。把DECLARE_DYNCREATE宏加入类的.H文件中,然后在全部需要访问此类对象的.CPP文件中包含这一模式。如果DECLARE_DYNCREATE包含在类定义中,那么IMPLEMENT_DYNCREATE必须包含在类工具中。