#define WTL_STD_CANCEL_BTN SHIDIF_CANCELBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN
#else
#define WTL_STD_CANCEL_B TN SHIDIF_SIZEDLGFULLSCREEN
#endif
出现断言错误!提示m_hWnd为空!
HDC dc = BeginPaint(&ps);
HPEN hPen;
hPen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
LineTo(dc, 240, 20);
DeleteObject(hPen);
EndPaint(&ps);
The NULL pointer is not allowed to the wcscpy function. The system behavior is unpredictable if a NULL pointer is used for either source or destination string pointer of the wcscpy function.
问题19:20090114
在封装一个函数的时候,应该尽可能的让函数功能单一。
例如:封装一个函数:DeleteFile()删除一个文件,如果成功则MessageBox“删除本文件成功”
那么MessageBox不应该放在DeleteFile中!而应该让DeleteFile返回一个值表示成功与否。
原因:MessageBox本并不是删除文件的功能。若把它加入DeleteFile会使函数通用性不强。
假设我要删除多个文件,只在所有文件删除所有文件之后,MessageBox"删除所有文件成功"
for(in i = 0; i < vector.size(); i++)
{
DeleteFile(i);
}
这样的话,每删除一个文件结束,都提示“删除本文件成功”
因此,应该尽可能保证一个函数只完成一个单一的功能。
问题20:20090115为何向ComboBox中插入Item后显示顺序不对?
::SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)_T("C"));
::SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)_T("B"));
::SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)_T("A"));
结果发现呈现的是:A、B、C。而我想要的是:C、B、A
原因:ComboBox有一个属性时Sort,即( CBS_SORT ),如果Sort为True,会自动给它排序。否则,每次都是插入末尾。以下是SDK中的说明:
If the combo box does not have the CBS_SORT style, the string is added to the end of the list. Otherwise, the string is inserted into the list, and the list is sorted.
问题21:20090119
loadIcon载入Icon后,不需要使用DeleteObject释放它。系统会默认释放。
但是Bitmap载入后,必须使用DeleteObject释放掉,否则会有内存泄露。
详情可以查看MSDN
问题22:使用引用参数和使用指针参数的小小区别
例子:需要实现一个函数,显示自制的MessageBox,函数名字定义如下有两种方式:
方式一
int OwnerMessageBox(HWND hParentWnd, // 父窗口句柄
LPWSTR pContent, // 提示信息内容
LPWSTR pTitle,
UINT uControl, //控件类型:进度条、radio、checkbox
UINT uType, // 对话框的类型,MB_OK或者其它
UINT uCountDown = 0, //倒计时的时间
UINT *pCheck = NULL, //如果是CheckBox,表示第一个CheckBox是否被选中,如果是Radio,表示选中的是哪一个Radio
LPWSTR strOne = NULL, //以下字符串都是显示Radio或者CheckBox使用的
LPWSTR strTwo = NULL,
LPWSTR strThree = NULL,
LPWSTR strFour = NULL)
方式二
int OwnerMessageBox(HWND hParentWnd, // 父窗口句柄
LPWSTR pContent, // 提示信息内容
LPWSTR pTitle,
UINT uControl, //控件类型:进度条、radio、checkbox
UINT uType, // 对话框的类型,MB_OK或者其它
UINT uCountDown = 0, //倒计时的时间
UINT &uCheck, //如果是CheckBox,表示第一个CheckBox是否被选中,如果是Radio,表示选中的是哪一个Radio
LPWSTR strOne = NULL, //以下字符串都是显示Radio或者CheckBox使用的
LPWSTR strTwo = NULL,
LPWSTR strThree = NULL,
LPWSTR strFour = NULL)
其中第七个参数是否有用取决于第四个参数uControl。现在我要调用此函数做一个只有进度条(没有CheckBox)的自制MessageBox。那么看看函数定义分别是方式一和方式二时,如何调用。
方式一:OwnerMessageBox(NULL, _T("test"), _T("test"), PROGRESS_TYPE, MB_OK);
其余的参数使用默认值即可。
方式二:
UINT uCheckState;
OwnerMessageBox(NULL, _T("test"), _T("test"), PROGRESS_TYPE, MB_OK, 0 ,uCheckState);
可以看到,使用方式二定义的函数,需要多定义一个此情况下(仅显示Progress控件)根本不需要的uCheckState变量,并且它之前的倒计时时间0也要写出来(也是没有用的)。可见,对于使用了引用参数的函数,
1、无法设定缺省值
2、在调用此函数前,必须先定义一个变量
那么我们再看看,我要实现一个有checkbox的自制MessageBox,对于两种函数定义又如何进行调用呢?
方式一:
UINT uCheckState;
OwnerMessageBox(NULL, _T("test"), _T("test"), CHECKBOX_TYPE, MB_OK, 0, &uCheckState, _T("If ask from now on?"));
方式二:
UINT uCheckState;
OwnerMessageBox(NULL, _T("test"), _T("test"), CHECKBOX_TYPE, MB_OK, 0, uCheckState, _T("If ask from now on?"));
这种情况下,两者差异不大。
问题23:从WTL移植到Win32时,一些无法使用的函数
CRect——atlmisc.h
问题24:#include和#pragma comment(lib, ……)的区别
按理说,这两个宏没有什么可比性,#include是包含指定的文件,#pragma comment(lib, ……)时把指定的库文件链接到工程中。但是在编程中遇到了这个情况,在Test.cpp中,有以下两行代码:
#include "../../Public/lib/library.h"
#pragma comment(lib, "../../../Public/lib/library.lib")
事实上,library.h和library.lib都是放在同一个目录下的,可是为什么这两个语句中,pragma comment却多写了一个../呢?(事实上,如果改成#pragma comment(lib, "../../Public/lib/library.lib")是会提示"无法找到library.lib")
原因:第一层 第二层 第三层 第四层
Total--Public --lib --library.h
--library.lib
--Common--Test.cpp
--UI --Main --main.sln
上面显示了文件夹的布局,include包含的文件路径是从当前Test.cpp网上翻2翻,再进入Public->lib得到的。而#pragma comment(lib,……)中所填的路径是根据当前程序main.sln往上翻3翻,再进入Public->lib得到的。这就是:#include和#pragma comment(lib, ……)的区别
因此,结论:
#include的路径是按照这个语句所在cpp的位置开始推算的。
#pragma comment的路径是根据整个工程sln所在位置开始推算的。(实践发现,此规则不仅仅是适用于pragma comment(lib,……),还适用于只要是#pragma comment的宏)
问题25:WTL中,使用CScrollImpl想让窗口自动调整大小,超过客户区域的时候显示滚动条。可是发现无论怎样设置初始客户区大小,总是出现水平和垂直滚动条,且水平和滚动范围很大。
我是如何使用CScrollImpl的:
class CTestDlg:
public CDialogImpl<CTestDlg>,
public CWinDataExchange<CTestDlg>,
public CScrollImpl<CTestDlg>
{
CTestDlg();
~CTestDlg();
BEGIN_MSG_MAP(CTestDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_SIZE, OnSize)
CHAIN_MSG_MAP(CScrollImpl<CTestDlg>)
REFLECT_NOTIFICATIONS()
END_MSG_MAP()
void DoPaint();
};
LRESULT CTestDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
DoDataExchange(FALSE);
RECT rcClient = {0};
GetClientRect(&rcClient);
SIZE sz = {0, 0};
sz.cx = rcClient.right - rcClient.left;
sz.cy = rcClient.bottom - rcClient.top;
SetScrollOffset(0, 0, FALSE);
SetScrollSize(sz);
return bHandled = FALSE;
}
LRESULT CTestDlg::OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
……
return TRUE;
}
原因:在于OnSize中默认的是bHandled = TRUE,于是不会再交给系统做默认处理。
解决方法:
LRESULT CTestDlg::OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
……
return bHandled = FALSE;
}
问题26:运算符的优先级==高于|
const UINT TYPE_ONE = 4;
const UINT TYPE_TWO = 8;
m_uControl = 2;
if(m_uControl == TYPE_ONE || m_uControl==TYPE_ONE |TYPE_TWO)
{
MessageBox(NULL, _T("Enter"), _T("test"), 0);
}
结果发现弹出MessageBox!
正确的写法:
if(m_uControl == TYPE_ONE || m_uControl==(TYPE_ONE |TYPE_TWO))
{
MessageBox(NULL, _T("Enter"), _T("test"), 0);
}
用括号把TYPE_ONE |TYPE_TWO括起来,保证他们先进行按位或操作。
问题27:不能随意使用=号来复制一个结构对象
typedef struct TestInfo
{
TCHAR szName[MAX_PATH]; // 名
TCHAR *szDetail; // 描述信息
TestInfo()
{
szName[0] = 0;
szDetails = NULL;
}
}TestInfo;
使用时,
TestInfo tempOne;
GetInfo(tempOne);//通过调用这个函数tempOne得到值
void SetTestInfo(TestInfo info)
{
g_Info = info;//错误!
}
结果发现出了SetTestInfo之后,g_Info的szDetails的值就是乱码了!
正确的复制方法是逐个成员复制
void SetTestInfo(TestInfo& info)
{
wsprintf(g_Info.szName, info.szName);
int len;
len = wcslen(info.szDetail);
g_Info.szDetail = new TCHAR[len+1];
wsprintf(g_Info.szDetail, info.szDetail);
}
最后记得通过detele[]释放g_Info.szDetail的空间。
问题28:如果Dialog具有DS_SETFOREGROUND属性,无论如何都无法把它隐藏掉!
由于粗心,不小心把某Dialog的属性设成了DS_SETFOREGROUND,以至于采用了ShowWindow(SW_HIDE); ShowWindow(SW_MINIMIZE);甚至把菜单最小化,都无法隐藏窗口。
问题29:如果一个类中只有static静态函数,那么使用函数时可以直接通过类名引用
例如:
class A
{
static void Fun();
};
调用:
A::Fun();
没有必要:
A test;
test.Fun();
问题30:使用多普达C730时,发现无论怎样都不能把程序导入手机中
原因:C730的安全级别比较高,需要安装安全证书。
C:/Program Files/Windows Mobile 6 SDK/Tools/Security/SDK Development Certificates/Certs.cab放在C730中安装即可。
问题31:如何清空ComboBox中的内容
方法一:
::SendMessage(hComboBox, CB_RESETCONTENT, 0, 0);
方法二:
for(int i = 0; i< iCount; i++)
{
::SendMessage(hComboBox, CB_DELETESTRING , i, 0);
}
结果发现,方法二始终无法删除干净,总是留下一项。
问题32:使用了Attach就一定要使用配套的Detach,否则会出现销毁窗口错误。
问题33:WTL下,对于HyperLink,设置文字内容需要调用SetLabel而不是SetWindowText!