VC FAQ

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 太老,如果我们用的是 VC6SDK ,有些东西是不支持的,解决办法是安装 VC789 或者更新 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 问:怎么保存和载入 Jpgpng 等格式的图片?

    答:使用 gdi+ 或者第三方的图片库,例如 paintlib ImageMagick 或者 ImageLibrary

2.2 问:怎么改变对话框的背景颜色,或者在对话框背景中绘制一个图片?

    答:修改对话框的背景颜色可以调用 CWinAppSetDialogBkColor, 不过不建议使用此函数。 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 。对于静态控件类型,调用 DCSetBkColor 即可。对于 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

    答:设置行的选中状态即可。我们知道 ListViewitem 结构中有 statestateMask 两个字段。其中 state 字段就是设置 listViewitem 的状态。 listView 控件的常见状态有选中和焦点两个。有了 state 状态为啥还搞一个 stateMask 呢?这个是为了设置影响到的状态。要修改 ListViewitem 状态,你不需要先获取每个状态值,之需要在 stateMask 中指定你想要修改的某个或者某几个状态即可。例如这里你需要修改 select 状态,之需要将 itemstatestateMask 都设置为LVIS_SELECTED

// MFC:

list.SetItemState(nItemToSelect,LVIS_SELECTED, LVIS_SELECTED );

// Win32 API:

ListView_SetItemState ( hwndYourList, nItemToSelect, LVIS_SELECTED, LVIS_SELECTED );

注意:默认 listview 控件是没有 LVS_SHOWSELALWAYS 属性,也就是说当前选择的 itemlistview 控件非激活状态下是不显示选中行的。

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 。这里使用了循环,保证能找到的我们的窗口。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值