error C2440: “static_cast”: 无法从“UINT (__thiscall CSizingControlBar::* )(CPoint)”转换为“LRESULT (__thiscall CWnd::* )(CPoint)”
error C2440: “static_cast”: 无法从“UINT (__thiscall CSizingControlBar::* )(CPoint)”转换为“LRESULT (__thiscall CWnd::* )(CPoint)” f:\tools\4bands ifx_xmm2130_ft\common\sizecbar.cpp 109
CWnd类,afx_msg LRESULT OnNcHitTest(CPoint point);
而在CSizingControlBar中是afx_msg UINT OnNcHitTest(CPoint point);
只要将这些UINT替换为LRESULT就可以了。
查找OnNcHitTest,将下面两行:
afx_msg UINT OnNcHitTest(CPoint point);//.h
UINT CTestDlg::OnNcHitTest(CPoint point);//.cpp
改为:
afx_msg LRESULT OnNcHitTest(CPoint point);//.h
LRESULT CTestDlg::OnNcHitTest(CPoint point);//.cpp
另外一个小问题:
CString atMyCmd;
atMyCmd+=0x0d;
编译时出现“operator+=不明确”。改正方法:atMyCmd+=(char)0x0d;因为从unsigned int转换到CString和char的等级都是标准转换,所以编译器无法判断到底应该转换到哪一个,所以就导致了这个问题,所以应该强制转换。
串口通讯中遇到的几个函数
串口工具中碰到的几个问题:
1、ClearCommError()
用途:清除串口错误或者读取串口现在状态
原型:BOOL ClearCommError(HANDLE hFile,LPDWORD lpErrors,LPCOMATAT lpStat)
参数:hFile:串口句柄
lpErrors:返回错误数值,错误代码:
1-CE_BREAK:检测到中断信号。也就是检测到某个字节数据缺少合法的停止位。
2-CE_FRAME:硬件检测到帧错误。
3-CE_IOE:通信设备发生输入/输出错误。
4-CE_MODE:设置模式错误,或者hFile值错误。
5-CE_OVERRUN:溢出错误,缓冲区容量不足,数据将丢失。
6-CE_RXOVER:溢出错误。
7-CE_RXPARITY:硬件检测到校验位错误。
8-CE_TXFULL:发送缓冲区已满。
lpStat:指向通信端口状态的结构变量,原型:
type struct _COMSTAT{
...
...
DWORD cbInQue;//输入缓冲区中的字节数
DWORD cbOutQue;//输出缓冲区的字节数
}
while (1) { bool bClearOk; bClearOk = ClearCommError( m_hComDev, &dwErrorFlags, &ComStat ); //如果函数调用成功,则返回值为非0;若函数调用失败,则返回值为0 }
if(!bClearOk) { return FALSE; } if (dwErrorFlags!=0)//错误数值 { end_time = clock(); if ((DWORD)((end_time-start_time)*1000/CLOCKS_PER_SEC) >= SERIALREAD_TIMEOUT) { return FALSE; } } else if ( ComStat.cbInQue >=data_size)//ComStat.cbInQue即为串口中当前含有的数据字节个数 { break; } else { end_time = clock(); if ((DWORD)((end_time-start_time)*1000/CLOCKS_PER_SEC) >= SERIALREAD_TIMEOUT) { return FALSE; }
2、clock()
c/c++中的计时函数是clock(),与其相关的数据类型是clock_t。MSDN中对该函数的定义:
clock_t clock(void);
该函数返回自程序开始运行的处理器时间,如果无可用信息,返回-1。转换返回值若以秒计需除以CLOCKS_PER_SEC。(在linux下是1000000,windows下是1000).也可以用clock()函数来计算机器运行一个循环或者处理其他事件到底花了多长时间。在要计时程序前后段分别调用clock函数,用最后一次的返回值减去前一次的返回值就得到运行的处理器时间,然后再转换为秒。如上例。
3、GetLastError()
作用就是取得上一个函数操作时所产生的错误代码。
DWORD GetLastError(void);通过调用,返回一个32位的数值。如:
DWORD dwError = GetLastError();
返回值的意义:
http://hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2/blog/item/c12e8f3fff6f54c17c1e71c1.html
其实用第三方类也挺方便的,不过貌似第三方类有个问题,具体的问题记不清了,后续继续研究串口通讯。先写到这,待续。。。^_^
.ini文件的读写
一直用Qt开发,无奈最近却要用MFC搞个东西,估计以后也不会用它开发,先记录下来,免得到时用时忘了。
ini文件由若干个节(Section)组成,每个Section由若干键(Key)组成,每个Key可以赋相应的值。读写ini文件实际上就是读写某个的Section中相应的Key的值。
MFC中读写ini文件:
1、把信息写入自己定义的.ini文件
BOOL WritePrivateProfileString(LPCTSTR lpAppName,
LPCTSTR lpKeyName,
LPCTSTR lpString,
LPCTSTR lpFileName //要写入的文件的文件名,若该ini文件与程序在同一个目录下,也可使用相对路径,否则要给出绝对路径。)
如:
::WritePrivateProfileString("CONFIGINFO","SOFT VERSION",m_SoftVer,".\\SET_NO2.ini");//将m_SoftVer的内容写进SET_NO2.ini
注,当使用相对路径时,\\前的.号不能丢掉了。
2、从.ini文件中读取信息
(1)、读取字符串
DWORD GetPrivateProfileString(LPCTSTR lpAppName,
LPCTSTR lpKeyName,
LPCTSTR lpDefault,
LPCTSTR lpReturnedString,
DWORD nSize,
LPCTSTR lpFileName)。
如:
::GetPrivateProfileString("CONFIGINFO","BAND","Error",strBandProof.GetBuffer(5),5,".\\SET_NO2.ini");
(2)、读取整数
UINT GetPrivateProfileInt(LPCTSTR lpAppName,
LPCTSTR lpKeyName,
INT nDefault,
LPCTSTR lpFileName)
如果用以下语句写入年龄信息:
::WritePrivateProfileString("Test","age","34",".\\exp.ini");
则可以用以下语句读取age的值:
int age;
age=::GetPrivateProfileInt("Test","age",0,".exp.ini");
Qt下:
写进.ini文件:
strIniDir = QCoreApplication::applicationDirPath() + "/config.ini"; QSettings *ConfigIni = new QSettings(strIniDir,QSettings::IniFormat,0); ConfigIni->setValue("Port",Params.PortName);
读取.ini文件:
strIniDir = QCoreApplication::applicationDirPath() +"/config.ini"; QSettings *ConfigIni = new QSettings(strIniDir,QSettings::IniFormat,0); PortName=ConfigIni->value("Port",PortName).toString();
回调函数
所谓的回调函数是指:按照一定的形式由开发人员定义并编写实现内容。使用回调函数,实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(也就是回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,也就是某种事情发生的时候,利用传递的函数地址调用回调函数,这时开发人员可以利用这个机会在回调函数中处理消息或完成一定的操作。回调函数只能是全局函数,或者是静态函数,因为这个函数只是在类中使用,所以为了维护类的完整性,我们用类的静态成员函数来做回调函数。
使用回调要完成以下工作:
1、获取函数地址:
获取函数地址很简单:只要使用函数名即可。比如test()是一个函数,则test就是该函数的地址。要将函数作为参数传递,只需要传递函数名即可。
2、声明一个函数指针:
声明一个函数指针,必须指定指针指向的函数类型,也就是声明应指定函数的返回类型以及函数的参数列表。如:
double cam(int);//函数原型
double (*fp)(int);//指针类型声明
因为cam为函数,所以(*fp)也为函数,所以,fp为函数指针
注:要声明指向特定类型的函数的指针,可以首先编写这种函数的原型,然后用(*fp)替换函数名,这样fp就是这类函数的指针。注意(*fp)必须用括号括起来。因为:
*fp(int)==>fp是一个返回指针的函数
(*fp)(int)==>fp是一个指向函数的指针
声明之后便可将相应函数的地址赋给它。如下所示:cam()的参数及返回类型必须与fp相同。
double cam(int);
double (*fp)(int);
fp=cam;
调用函数原型:
void test(int n,double(*fp)(int));第二个参数是一个函数指针,它指向的函数接受一个int参数,并返回一个double值。要让test使用cam()函数,则需将cam()的地址传给它,即:test(3,cam);
3、使用函数指针来调用函数
double cam(int);
double (*fp)(int);
fp=cam;
double x=cam(4);//使用函数名调用cam()
double y=(*fp)(5);//使用指针fp调用cam()
c++也允许像使用函数名那样使用fp:double y=fp(5);不过第一种方式更能显示出正在使用函数指针。
回调有两个主要缺点:1> 它们不是类型安全的。我们从来都不能确定处理函数使用了正确的参数来调用回调。2> 回调和处理函数是非常强有力的联系在一起的,因为处理函数必须要知道调用哪个回调。
c语言声明的优先级规则
规则:
A:声明从它的名字开始读取,然后按照优先级顺序依次读取;
B:优先级从高到低依次是:
B1、声明中被括号括起来的那部分;
B2、后缀操作符:括号()表示这是一个函数,而[]表示这是一个数组
B3、前缀操作符:*表示“指向...的指针”
C:如果const或volatile关键字的后面紧跟类型说明符(如int ,long等),那么它作用于类型说明符,在其他情况下,const或volatile关键字作用于它左边紧邻的指针星号。
分析:char *const *(*next)();
用优先级规则分析:
A:首先,看变量名“next”,并且它直接被括号括住;
B1:所以先把括号里面的东西作为一个整体,得出“next是一个指向...的指针”;
B:然后考虑括号外面的东西,在星号前缀与括号后缀之间作出选择;
B2:B2规则告诉我们优先级高的是右边的函数括号,所以得出“next是一个函数指针,指向一个返回...的函数”;
B3:然后处理前缀*,得出指针所指内容;
C:最后,把char *const解释为指向字符的常量指针。
即:next是一个指针,它指向一个函数,该函数返回另一个指针,该指针指向一个类型为char的常量指针。