1、
1.1 问:尝试使用 C++ 标准库中的类 ( 例如 cout , cin 或者 string) ,编译器却给出 C2065 提示说标示符未定义 (undeclared identifier)
答:这个由于标准库中的类或者变量等的定义都是在 std 命名空间。需要我们在使用标准库中的标识前面加上 std:: 前缀。当然,为了简单,可以在文件头引入命令空间 use namespace std
1.2 问:怎么知道我的代码是否正在使用 iostream
答: iostream 库头文件是 iostream.h ,带有 .h 扩展名的,而标准 stl
1.3 问:我试着调用一个 Windows API ,但是编译器给出 C2065
答:一般这是由于调用了某个 Window API 但是没有包含 API 对应的头文件。我们调用一个 API 函数,需要包含申明此函数的头文件。例如我们调用了 SHBrowseForFolder 这个 shell 函数,我们需要包含头文件 sheobj.h 。另外,在某些时候我们包含了头文件,但是还是有这个提示,那么很有可能是 windows 版本或者控件版本问题,通常,对于通用控件来说出现这个的比较多。第一个是我们的 SDK 太老,如果我们用的是 VC6 的 SDK ,有些东西是不支持的,解决办法是安装 VC7 , 8 , 9 或者更新 PSDK 。对于 VC 程序来说,向导生成的 stdafx.h
WINNVER: Windows 版本(应用于 9x/me/NT
_WIN32_WINDOWS: Windows 9x/me
_WIN32_WINNT: Windows NT
_WIN32_IE:
有些 API( 特别是有些通用控件 ) 需要最新版本的支持,我们需要修改这些宏定义为合适的值,保证调用的正确性。实际上你看看 commctrl.h
1.4 问:我尝试调用一个 Windows API ,但是连接起给出 LNK2001
答:调用 Windows API ,除了需要包含函数申明的头文件外,还需要告诉链接器在什么地方找到这个函数的实现,也就是说需要将此 API 实现的库链接进去。这些是通过 lib( 导入库 ) 。导入库是一个 lib 文件包含了对应库 dll 的所有导出函数列表信息,通过这个可以保证程序在运行的时候正确的加载所需的依赖库,并且找到调用函数的实现,跳转到对应函数代码处执行。把对应库加入到链接包含文件中的方法有两种,第一:在工程属性页中选中链接页进行设置;第二个是使用 #pragma comment(lib, “usedLibName”)
1.5 问:在编译 ATL 工程的时候,提示 Lnk2001 main
答:这是因为你在 ATL 工程中调用了 CRuntime 函数。 ATL 项目为了尽可能的缩减工程的体积,默认是不会链接 CRT 库。如果你调用了 CRT 函数,那你就得把 CRT 库链接进去。实际上你只需要去掉 _ATL_MIN_CRT
1.6 问:提示链接错误 Lnk2001 :找不到 _beginthreadex|_endthreadex
答:通常这发生在使用 MFC 程序,而我们使用的运行库为单线程的 CRT 。由于 MFC 程序使用线程,它需要多线程 CRT ,这个看看 msdn 关于 _beginthread API 就知道了,明确说了此 API 需要多线程 CRT
2、 Window UI
2.1 问:怎么保存和载入 Jpg 、 png
答:使用 gdi+ 或者第三方的图片库,例如 paintlib , ImageMagick 或者 ImageLibrary
2.2
答:修改对话框的背景颜色可以调用 CWinApp 的 SetDialogBkColor, 不过不建议使用此函数。 Msdn 明确说了,修改对话框的背景颜色,处理 WM_CTRLCOLOR 消息。另外处理对话框的背景颜色或者在对话框背景中绘制图片,可以处理 WM_ERASEBKGND 。对于对话框来说,不要处理 WM_PAINT
2.3
答:实际上这个不是按钮的问题,而是在执行过程中按钮点击事件如何得到响应的问题。你在单线程程序中进行复杂运算,对话框消息得不到处理。解决这个问题有两个办法:多线程或者在执行复杂运算过程中定期 pump 对话框消息。对于方法一的多线程,可以将复杂运算放在工作线程中执行。对于方法二, MFC
Void ProcessMsg()
{
CWinApp *pApp = AfxGetApp();
MSG msg;
While( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
pApp->PumpMessage();
}
你只需要在执行复杂运算过程中定期执行以下 ProcessMsg()
2.4
答:很简单,处理 WM_SETCURSOR 消息即可。在消息中调用 SetCursor() 来设置你想要的光标。由于 WM_SETCURSOR 在你鼠标移动的时候都会调用,因此尽量不要在此函数处理中进行复杂的调用,比如进行文件或者其他的 IO
2.5
答:利用 API SetWindowPos
// MFC
yourWindows.SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE)
// API
SetWindowPos(yourWindows, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
相反,如果想取消置顶显示,设置 wndNoTopMost 和 HWND_NOTOPMOST
2.6 问:如果将一个 report 模式的 listView
答:只需要设置全行选中扩展属性即可 LVS_EX_FULLROWSELECT
yourList.SetExtendStyle(LVS_EX_FULLROWSELECT);
2.7
答:对于 MFC 程序来说,在父窗口中处理 WM_CTRLCOLOR 。对于静态控件类型,调用 DC 的 SetBkColor 即可。对于 Win32 程序来说,在父窗口中处理 WM_CTRLCOLORSTATIC
HBRUSH CYourDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if ( pWnd->GetSafeHwnd() == GetDlgItem(IDC_LABEL1)->GetSafeHwnd() &&
CTLCOLOR_STATIC == nCtlColor )
{
m_bkbrush.CreateSolidBrush ( RGB(255,0,0) );
pDC->SetBkMode ( TRANSPARENT );
return m_bkbrush;
}
return hbr;
}
// Win32 API:
LRESULT CALLBACK YourDlgProc(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
static HBRUSH hbrBkcolor:
switch (message)
{
case WM_INITDIALOG:
hbrBkcolor = CreateSolidBrush ( RGB(255,0,0) );
return TRUE;
break;
case WM_CTLCOLORSTATIC:
{
HDC hdc = (HDC) wParam;
HWND hwndStatic = (HWND) lParam;
if ( hwndStatic == GetDlgItem ( hDlg, IDC_LABEL1 ))
{
SetBkMode ( hdc, TRANSPARENT );
return (LRESULT) hbrBkcolor;
}
}
break;
// ...
}
return FALSE;
}
2.8 问:如何编程选择 listView 控件中的某一个 item
答:设置行的选中状态即可。我们知道 ListView 的 item 结构中有 state 和 stateMask 两个字段。其中 state 字段就是设置 listView 的 item 的状态。 listView 控件的常见状态有选中和焦点两个。有了 state 状态为啥还搞一个 stateMask 呢?这个是为了设置影响到的状态。要修改 ListView 的 item 状态,你不需要先获取每个状态值,之需要在 stateMask 中指定你想要修改的某个或者某几个状态即可。例如这里你需要修改 select 状态,之需要将 item 的 state 和 stateMask 都设置为LVIS_SELECTED
// MFC:
list.SetItemState(nItemToSelect,LVIS_SELECTED, LVIS_SELECTED );
// Win32 API:
ListView_SetItemState ( hwndYourList, nItemToSelect, LVIS_SELECTED, LVIS_SELECTED );
注意:默认 listview 控件是没有 LVS_SHOWSELALWAYS 属性,也就是说当前选择的 item 在 listview
2.9 问:我的 list 控件和 tree 控件在 debug 下运行 OK ,但是在 release
答:很可能是因为你使用到 LVITEM 或者 TVITEM 没有初始化导致。在所有使用的地方先初始化试试。例如:LVITEM lvi = {0}; TVINSERTSTRUCT tvins = {0};
2.10
答:使用 ”/r/n” 来换行。如果你使用 ”/r” 或者 ”/n” 或者 ”/n/r”
2.11
答:使用 SHBrowseForFolder()
2.12
答:处理 WM_GETMINMAXINFO 即可。设置最大和最小 trace
LRESULT OnGetMinMaxInfo ( WPARAM wParam, LPARAM lParam )
{
MINMAXINFO* pmmi = (MINMAXINFO*) lParam;
pmmi->ptMinTrackSize.x = 100;
pmmi->ptMinTrackSize.y = 150;
pmmi->ptMaxTrackSize.x = 600;
pmmi->ptMaxTrackSize.y = 400;
return 0;
}
3、
3.1
答:利用控制台函数 FillConsoleOutputCharacter() FillConsoleOutputAttribute() 函数。在使用这些函数之前,你得获取到控制台句柄,利用 GetStdHandle()
3.2
答:利用 SetConsoleTextAttribute() 和 SetConsoleOutputAttribut() 。当然,控制台不支持下划线和加粗。如果想要这种效果 ….
3.3 问:在我的 GUI
答:很简单。直接调用 AllocConsole() API
同时,如果程序创建了一个控制台,那么关闭控制台会导致应用程序的关闭。
3.4
void DisableClose()
{
char buf[100];
wsprintf ( buf, _T("some crazy but unique string that will ID ")
_T("our window - maybe a GUID and process ID") );
SetConsoleTitle ( (LPCTSTR) buf );
// Give this a chance - it may fail the first time through.
HWND hwnd = NULL;
while ( NULL == hwnd )
{
hwnd = ::FindWindowEx ( NULL, NULL, NULL, (LPCTSTR) buf );
}
// Reset old title - we'd normally save it with GetConsoleTitle.
SetConsoleTitle ( _T("whatever") );
// Remove the Close menu item. This will also disable the [X] button
// in the title bar.
HMENU hmenu = GetSystemMenu ( hwnd, FALSE );
DeleteMenu ( hmenu, SC_CLOSE, MF_BYCOMMAND );
}
需要注意的是上述在 FindWindowEx 使用了循环。在调试运行下一般来说第一次就能到 Find 到控制台窗口,但是在普通运行模式下,第一次基本上都找不到窗口,不知道是不是 MS 的一个 Bug