一些细碎的注意点

最近项目开始忙起来了,不能像之前每天发好几篇博客了,那就开一篇文章记录一下平时遇到的一些问题,供以后参考。
问题1:一个继承自COwnerDraw的重绘控件无法正常绘制
原因:在使用此控件的Dialog中,漏掉了 REFLECT_NOTIFICATIONS() ,此函数能够反射消息给控件处理。
 
问题2:WTL下,建立了一个Dialog,通过OnSize和SetFullScreen等方法都始终不能让它占满屏幕
解决: bHandled = FALSE;    之前是bHandled = TRUE;    
 
问题3:1-1/6 = ?
解决:答案是1, 因为1/6等于0, 怪不得每次无论怎么调整变量的值(变量就是1/6)都不管用。以后不要再犯这种低级错误!
 
问题4:ListView总是有水平滚动条
解决:m_listview.SetColumnWidth(GetSystemMetrics(SM_CXSCREEN) - GetSystemMetrics(SM_CXSCROLL) - 2* GetSystemMetrics(SM_CXBORDER ));
 
问题5:Unhandled exception at 0x80079cec in NetQinAntiVirus.exe: 0xC0000030:
原因:数组越界,或者使用了没有申请的野空间
例如:int test[2];
            test[2] = 1;     出错!
又如:
          struct A
          {
                int i;
                float j;
          }
            A a;
            a.i = 5;         出错!
 
 
问题6:自绘的ListView中,发现ListView的宽度不能调整成占满屏幕
原因:m_lv.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER);
事实上,ListView的宽度是在这里设定的,而我想在MeasureItem中通过GetClientRect获得客户区宽度,然后把Item的宽度设置成客户区宽度。事实上,客户区宽度就是之前SetColumnWidth设定的宽度了。
解决:
m_lv.SetColumnWidth(0, GetSystemMetrics(SM_CXSCREEN) );
 
问题7:当焦点放在comboBox上时,总是在comboBox里呈现光标
原因:此时comboBox的type属性是DropDown,在comboBox里面其实还嵌入了一个Edit控件,这种属性的comboBox能够让用户手动编辑内容。
解决方法:把comboBox的type属性改成Drop List即可。这就是一个一般的combo box
 
问题8:WTL下,如何让Dialog右上角具有小叉?
解决:创建Dialog时设定其属性。
#ifdef WIN32_PLATFORM_PSPC
#define WTL_STD_CANCEL_BTN  SHIDIF_CANCELBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN
#else
#define WTL_STD_CANCEL_B TN  SHIDIF_SIZEDLGFULLSCREEN
#endif
 
class CMainDlg : public CStdDialogImpl<CMainDlg, WTL_STD_CANCEL_BTN>
……
};
设定了 WTL_STD_CANCEL_BTN 后,WTL自动就会按照这种方式创造Dialog。
 
问题9:
对于类中定义的数据,析构时要释放掉申请的空间。
ImageList_Create之后,再ImageList_ReplaceIcon才能载入ICON
 
问题10:字符串转换
MultiByteToWideChar
  函数功能:该函数映射一个字符串到一个宽字符(unicode)的字符串。由该函数映射的字符串没必要是多字节字符组。
  函数原型:int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cchMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
  参数:
  CodePage: 指定执行转换的代码页,这个参数可以为系统已安装或有效的任何代码页所给定的值。你也可以指定其为下面的任意一值:
  CP_ACP:ANSI代码页;CP_MACCP:Macintosh代码页;CP_OEMCP:OEM代码页;
  CP_SYMBOL:符号代码页(42);CP_THREAD_ACP:当前线索ANSI代码页;
  CP_UTF7:使用UTF-7转换;CP_UTF8:使用UTF-8转换。
 
char转成TCHAR:MultiByteToWideChar( CP_ACP, 0, lpchar, -1, lptchar, cbSize );
TCHAR转成char:WideCharToMultiByte( CP_ACP, 0, lptchar, -1, lpchar, cbSize, NULL, NULL);
 
问题11:void SetItemImage( int iIdx = -1, IMAGELISTSTRUCT imageList)错误!
提示error C2548:  missing default parameter for parameter 2
解决方法:void SetItemImage (IMAGELISTSTRUCT imageList, int iIdx = -1)
分析:给函数参数赋默认值时,之后的参数都需要默认值。

 

 
问题12:页面刷新时,Static控件闪过白色
在一个背景色为渐进色的Dialog A中,有经过处理的透明Static控件。发现在从Dialog B切换到A时,Static控件闪过白色。
解决方案:处理Dialog A的WM_ERASEBKGND消息,使得不要绘制背景。
原因:我的背景绘制时在WM_PAINT中处理的,切换时触发画背景,系统做了默认画背景操作,使得Static控件区域绘制成白色。
 
问题13:无法向ListView插入多列(即虽然能够插入一列,但再插入其他列时失败)
原因:LVITEM lvI;
            lvI.mask = LVIF_PARAM;//若使用这个参数,无法插入多列!
解决方法:取掉 LVIF_PARAM即可。
 
问题14:创建了一个Dialog,上面有一个Static控件,通过CStaticImpl m_stcBitmap;声明,且已经进行子类化了。结果在OnSize中的以下语句: m_stcBitmap.MoveWindow(rcBmp.left, rcBmp.top, rcBmp.Width(), rcBmp.Height(), TRUE);
出现断言错误!提示m_hWnd为空!
原因:WM_SIZE消息可能在子类化之前被调用,而这时候m_stcBitmap.m_hWnd是空的!
解决防范:在OnSize的使用m_stcBitmap之前判断一下m_stcBitmap.m_hWnd是否为空。
 
问题15:如何画线?
1、创建画笔(如果仅仅使用默认的黑色,则不必创建画笔,直接画线即可)
2、画线
例如:
PAINTSTRUCT ps;
 HDC dc = BeginPaint(&ps);
 HPEN hPen;
 hPen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
SelectObject(dc, hPen);
 MoveToEx(dc, 0, 20, NULL);
 LineTo(dc,  240, 20);
 DeleteObject(hPen);
 EndPaint(&ps);
 
问题16:GetDC
GetDC和GetWindowDC后,都需要使用ReleaseDC释放。
 
问题17:申请堆空间
malloc与free
new与delete
一定要配对使用!

问题18:20081230
封装了一个CStaticImpl控件,具有CStatic的特性。并且通过处理CStaticImpl的WM_PAINT消息能够在Static上绘制图片。但是不知怎么回事,始终绘制不出图片。检查发现是根本没有进入WM_PAINT消息处理!于是看是否在Dialog的消息宏定义中上加上REFLECT_NOTIFICATIONS(),明明有嘛!
最后的解决方法竟然是: 在Dialog的WM_SIZE中调整Static控件的位置!费解!
不过我的Dialog是继承自CDialogImpl的。而对于继承自CStdDialogImpl的Dialog,就不存在必须调整控件位置才能绘制的问题哦。奇怪哦。
先记下来吧。以后再仔细分析分析。

问题19: 20081231
想要显示10%形式的内容在Static控件中,结果总是显示不出百分号
错误例子:
        TCHAR strPercent[10];
wsprintf(strPercent, _T("%d%"), uPos);
m_stcPercent.SetWindowText(strPercent);
原因:%本身是转译字符,要打出它需要指明它不是转译的。
正确方式:
        TCHAR strPercent[10];
wsprintf(strPercent, _T("%d%s"), uPos, _T("%"));
m_stcPercent.SetWindowText(strPercent);
也可以:        
        TCHAR strPercent[10];
wsprintf(strPercent, _T("%d%%"), uPos);
m_stcPercent.SetWindowText(strPercent);
 
问题20:lstrcpy的使用
TCHAR* strSource = NULL;
TCHAR  strDest[64];
lstrcpy(strDest,  strSource);
程序执行到 lstrcpy函数时崩溃!
原因: 在lstrcpy函数中,参数不能是NULL指针!否则系统行为无法预测!

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!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值