1.DLL的InitInstance和ExitInstance不会执行
Settings->C/C++->Preprocessor->Preprocessor Definitions->少了一个_USRDLL
_USRDLL是编译宏选项,MFC Library支持两种类型的DLL:_USRDLL 和_AFXDLL._USRDLL 模式需要CWinApp对象来执行dll使用的MFC Library窗口的初始化和清除.而_AFXDLL不需要CWinApp对象,因为他与使用他的应用程序共享MFC Library,他不需要CWinApp提供初始化和清除工作
2.为避免死锁,请对所有多重加锁的语句都按照相同顺序加锁。比如
Thread1:
lock A
lock B
unlock B
unlock A
Thread2:
不要
lock B
lock A
unlock A
unlock B
而要
lock A
lock B
unlock B
unlock A
3.消息过滤函数返回值不能瞎写,return 0 的话可能连窗体都创建不出来,你还找不到错误!
血的教训
E:/cary/主线/trunk/app/PayAssistant新/PayAssistant/Debug/image/pay_cancel_normal.bmp
4.>>>,称为逻辑右移,右移n位,空位补0。>>称为算术右移,右移n位,空位用原最高位的位值补足,相当于E/2n,能保留原数的符号
5.好多是否忘记了加;是因为函数名没有解析成功当成字符串了 看看是否遗漏了添加什么头文件
6.血的教训 mfc控件千万别摆在哪就认为他在哪 一定要自己去将他的位置固定住!否则在不同的系统中,控件的位置有所不同
7.虚拟列表(virtual list control) 可以解决上万条数据插入的时候比较缓慢 http://blog.youkuaiyun.com/denglei265/article/details/15335169
8.多态运用 在使用多态时,在new和delete时一定要保持原有对象类型,不能在new时就进行强制转换,否则会在析构时出现问题
CInherit *p_cb=new CInherit();
((CBase*)p_cb)->call();
delete p_cb;
但运用时可以将基类析构函数写成虚函数,这样delete就会走子类的析构了
9.有元函数
设置成有元函数和类 就可以访问其类中各种权限的何种资源
class A
{
…
public:
friend class B;
…
};
经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。
10.为什么不要轻易在.h中写实现,注意:如果在预编译中引用了这个.h,或者这个.h是大家都用的 另外两个.h互相引用了 ,就会出现重定义的情况!!所以声明和定义要分开写这样是最理想的,除非你能保证不会重复引用造成重定义!
11.回调函数为什么一定要是全局或者类的静态函数呢?
在使用STL算法时,如:sort函数的第三个参数
template<classRandomAccessIterator, class Predicate>
void sort(
RandomAccessIterator _First,
RandomAccessIterator _Last,
Predicate _Comp
);
Predicate是个函数指针
当我们调用sort时,_Comp会被windows调用,但是windows并不借助任何函数来调用它,所以windows要先知道该函数的地址,
有两种方式
1. 全局函数
2.静态的类函数
回调函数一般都需要this指针来置顶
12.抽象工厂用的也多,状态模式也常用,命令模式也挺常见
13.Sqlite3 修改表字段功能函数
13.根据进程句柄查找进程路径
Settings->C/C++->Preprocessor->Preprocessor Definitions->少了一个_USRDLL
_USRDLL是编译宏选项,MFC Library支持两种类型的DLL:_USRDLL 和_AFXDLL._USRDLL 模式需要CWinApp对象来执行dll使用的MFC Library窗口的初始化和清除.而_AFXDLL不需要CWinApp对象,因为他与使用他的应用程序共享MFC Library,他不需要CWinApp提供初始化和清除工作
2.为避免死锁,请对所有多重加锁的语句都按照相同顺序加锁。比如
Thread1:
lock A
lock B
unlock B
unlock A
Thread2:
不要
lock B
lock A
unlock A
unlock B
而要
lock A
lock B
unlock B
unlock A
3.消息过滤函数返回值不能瞎写,return 0 的话可能连窗体都创建不出来,你还找不到错误!
血的教训
E:/cary/主线/trunk/app/PayAssistant新/PayAssistant/Debug/image/pay_cancel_normal.bmp
4.>>>,称为逻辑右移,右移n位,空位补0。>>称为算术右移,右移n位,空位用原最高位的位值补足,相当于E/2n,能保留原数的符号
5.好多是否忘记了加;是因为函数名没有解析成功当成字符串了 看看是否遗漏了添加什么头文件
6.血的教训 mfc控件千万别摆在哪就认为他在哪 一定要自己去将他的位置固定住!否则在不同的系统中,控件的位置有所不同
7.虚拟列表(virtual list control) 可以解决上万条数据插入的时候比较缓慢 http://blog.youkuaiyun.com/denglei265/article/details/15335169
8.多态运用 在使用多态时,在new和delete时一定要保持原有对象类型,不能在new时就进行强制转换,否则会在析构时出现问题
CInherit *p_cb=new CInherit();
((CBase*)p_cb)->call();
delete p_cb;
但运用时可以将基类析构函数写成虚函数,这样delete就会走子类的析构了
9.有元函数
设置成有元函数和类 就可以访问其类中各种权限的何种资源
class A
{
…
public:
friend class B;
…
};
经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。
10.为什么不要轻易在.h中写实现,注意:如果在预编译中引用了这个.h,或者这个.h是大家都用的 另外两个.h互相引用了 ,就会出现重定义的情况!!所以声明和定义要分开写这样是最理想的,除非你能保证不会重复引用造成重定义!
11.回调函数为什么一定要是全局或者类的静态函数呢?
在使用STL算法时,如:sort函数的第三个参数
template<classRandomAccessIterator, class Predicate>
void sort(
RandomAccessIterator _First,
RandomAccessIterator _Last,
Predicate _Comp
);
Predicate是个函数指针
当我们调用sort时,_Comp会被windows调用,但是windows并不借助任何函数来调用它,所以windows要先知道该函数的地址,
有两种方式
1. 全局函数
2.静态的类函数
回调函数一般都需要this指针来置顶
12.抽象工厂用的也多,状态模式也常用,命令模式也挺常见
13.Sqlite3 修改表字段功能函数
BOOL CInvoiceInfoTable::ChangeRowNature()
{
//先将表重命名
char achsql[MAX_PATH]={0};
Safe_sprintf(achsql,sizeof(achsql),"ALTER TABLE ClassStruct RENAME TO ClassStruct2008");
string sTemp;
if (!ExecuteSql(sTemp))
{
GEILOG("ExecuteSql false");
return FALSE;
}
//重新创建表
Safe_sprintf(achsql,sizeof(achsql),"CREATE TABLE IF NOT EXISTS ClassStruct('Name' TEXT, 'Class' TEXT);");
string sTemp;
if (!ExecuteSql(sTemp))
{
GEILOG("ExecuteSql false");
return FALSE;
}
Safe_sprintf(achsql,sizeof(achsql),"INSERT INTO ClassStruct(Name,Class)SELECT (Name,Class) FROM ClassStruct2008");
string sTemp;
if (!ExecuteSql(sTemp))
{
GEILOG("ExecuteSql false");
return FALSE;
}
Safe_sprintf(achsql,sizeof(achsql),"DROP TABLE ClassStruct2008");
string sTemp;
if (!ExecuteSql(sTemp))
{
GEILOG("ExecuteSql false");
return FALSE;
}
}
13.根据进程句柄查找进程路径
void GetProcessFilePath(IN HANDLE hProcess, OUT CString& sFilePath)
{
sFilePath = _T("");
TCHAR tsFileDosPath[MAX_PATH + 1];
ZeroMemory(tsFileDosPath, sizeof(TCHAR)*(MAX_PATH + 1));
if (0 == GetProcessImageFileName(hProcess, tsFileDosPath, MAX_PATH + 1))
{
return;
}
// 获取Logic Drive String长度
UINT uiLen = GetLogicalDriveStrings(0, NULL);
if (0 == uiLen)
{
return;
}
PTSTR pLogicDriveString = new TCHAR[uiLen + 1];
ZeroMemory(pLogicDriveString, uiLen + 1);
uiLen = GetLogicalDriveStrings(uiLen, pLogicDriveString);
if (0 == uiLen)
{
delete[]pLogicDriveString;
return;
}
TCHAR szDrive[3] = TEXT(" :");
PTSTR pDosDriveName = new TCHAR[MAX_PATH];
PTSTR pLogicIndex = pLogicDriveString;
do
{
szDrive[0] = *pLogicIndex;
uiLen = QueryDosDevice(szDrive, pDosDriveName, MAX_PATH);
if (0 == uiLen)
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
break;
}
delete[]pDosDriveName;
pDosDriveName = new TCHAR[uiLen + 1];
uiLen = QueryDosDevice(szDrive, pDosDriveName, uiLen + 1);
if (0 == uiLen)
{
break;
}
}
uiLen = _tcslen(pDosDriveName);
if (0 == _tcsnicmp(tsFileDosPath, pDosDriveName, uiLen))
{
sFilePath.Format(_T("%s%s"), szDrive, tsFileDosPath + uiLen);
break;
}
while (*pLogicIndex++);
} while (*pLogicIndex);
delete[]pLogicDriveString;
delete[]pDosDriveName;
}