RELATEED CONSULTING
相关咨询
选择下列产品马上在线沟通
服务时间:9:30-18:00
你可能遇到了下面的问题
关闭右侧工具栏
VC编程指南67篇
  • 作者:xiaoxiao
  • 发表时间:2020-12-23 10:39
  • 来源:未知

摘自"水木清华"  1. 如何获取应用程序的实例句柄?   应用程序的 实例句柄保存在CWinAppIm_hInstance 中,可以这么调用   AfxGetInstancdHandle获得句柄.     Example: HANDLE hInstance=AfxGetInstanceHandle();  2. 如何通过代码获得应用程序主窗口的 指针?    主窗口的 指针保存在CWinThread::m_pMainWnd中,调用 AfxGetMainWnd实现。     AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //使程序最大化.  3.如何在程序中获得其他程序的 图标?     两种方法:       (1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle,       (2) SDK函数 SHGetFileInfo获得有关文件的 很多信息,如大小图标,属性,          类型等.         Example(1): 在程序窗口左上角显示 NotePad图标.          void CSampleView: OnDraw(CDC * pDC)            {               if( :: SHGetFileInfo(_T("c://pwin95//notepad.exe"),0,                    &stFileInfo,sizeof(stFileInfo),SHGFI_ICON))                  {                    pDC ->DrawIcon(10,10,stFileInfo.hIcon);                  }                 }           Example(2):同样功能,Use ExtractIcon Function           void CSampleView:: OnDraw(CDC *pDC)             {               HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T                ("NotePad.exe"),0);               if (hIcon &&hIcon!=(HICON)-1)                  pDC->DrawIcon(10,10,hIcon);               }  说明: 获得notepad.exe的路径正规上来说用GetWindowsDirectory 函数得到,     如果是调用 win95下的画笔,应该用访问注册表的方法获得其路径,要作成一个    比较考究的程序,考虑应该全面点.  4.如何编程结束应用程序?如何编程控制windows的重新引导?     这是个很简单又是编程中经常要遇到的问题.    第一问,向窗口发送 WM_CLOSE消息,调用 CWnd::OnClose成员函数.允许对用户提示   是否保存修改过的数据.    Example: AfxGetMainWindow()->SendMessage(WM_CLOSE);   还可以创建一个自定义的函数 Terminate Window     void Terminate Window(LPCSTR pCaption)     {         CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption);              if (pWnd)                 pWnd ->SendMessage(WM_CLOSE);     }  说明: FindWindow函数不是提倡的做法,因为它无法处理标题栏自动改变,比如  我们要检测 Notepad是不是已运行而事先不知道Notepad的标题栏,这时 FindWindow就  无能为力了,可以通过枚举 windows任务列表的办法来实现。 在 机械出版社  "Windows 95 API开发人员指南"一书有比较详细的介绍,这里就不再多说乐。 第二问,Use ExitWindowsEx Function函数控制系统是重新引导,还是重启 windows.  前面已经有人讲过乐,就不再提了。  5.怎样加栽其他的应用程序?   我记得这好象是出场频度很高的问题。   三个SDK函数 winexec, sh/*llexecute,createprocess可以使用。    WinExec最简单,两个参数,前一个指定路径,后一个指定显示方式.后一个参数 值得说一下,比如泥用 SW_SHOWMAXMIZED方式去加栽一个无最大化按钮的 程序,呵呵 就是Neterm,calc等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。   Sh/*llExecute较 WinExex灵活一点,可以指定工作目录,下面的 Example就是直接 打开 c:/temp/1.txt,而不用加栽与 txt文件关联的应用程序,很多安装程序完成后 都会打开一个窗口,来显示Readme or Faq,偶猜就是这么作的啦.   Sh/*llExecute(NULL,NULL,_T("1.txt"),NULL,_T("c://temp"),SW_SHOWMAXMIZED);   CreateProcess最复杂,一共有十个参数,不过大部分都可以用NULL代替,它可以   指定进程的安全属性,继承信息,类的优先级等等.来看个很简单的 Example:      STARTUPINFO stinfo;   //启动窗口的信息      PROCESSINFO procinfo;  //进程的信息    CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE, NORMAL_PRIORITY_      CLASS,NULL,NULL, &stinfo,&procinfo);   6. 确定应用程序的 路径      前些天好象有人问过这个问题.       Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名。         Example:          TCHAR exeFullPath[MAX_PATH]; // MAX_PATH在API中定义了吧,好象是128          GetModuleFileName(NULL,exeFullPath,MAX_PATH)    7. 获得各种目录信息       Windows目录: Use "GetWindowsDirectory“       Windows下的system目录: Use "GetSystemDirectory"       temp目录: Use "GetTempPath "        当前目录: Use "GetCurrentDirectory"      请注意前两个函数的第一个参数为 目录变量名,后一个为缓冲区; 后两个相反.    8. 如何自定义消息       也有人问过的,其实不难。         (1) 手工定义消息,可以这么写 #define WM_MY_MESSAGE(WM_USER+100),           MS 推荐的至少是 WM_USER+100;         (2)写消息处理函数,用 WPARAM,LPARAM返回LRESULT.            LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam)             {               //加入你的处理函数             }          (3)  在类的 AFX_MSG处进行声明,也就是常说的"宏映射" 9-16: 对窗口的 控制 9. 如何改变窗口的 图标?   向窗口发送 WM_SECTION消息。   Example:     HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON);     ASSERT(hIcon);     AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM) hIcon); 10. 如何改变窗口的 缺省风格?     重栽 CWnd:: PreCreateWindow 并修改CREATESTRUCT结构来指定窗口风格和其他    创建信息.    Example: Delete "Max" Button and Set Original Window's Position and Size           BOOL CMainFrame::  PreCreateWindow (CREATESTRUCT &cs)     {            cs.style &=~WS_MAXINIZEMOX;      cs.x=cs.y=0;      cs.cx=GetSystemMetrics(SM_CXSCREEN/2);      cs.cy=GetSystemMetrics(SM_CYSCREEN/2);       return CMDIFramewnd ::PreCreateWindow(cs);         } 11.  如何将窗口居中显示?       Easy, Call Function CWnd:: Center Windows                Example(1):  Center Window( );  //Relative to it's parent         // Relative to Screen        Example(2):  Center Window(CWnd:: GetDesktopWindow( ));         //Relative to Application's MainWindow        AfxGetMainWnd( ) -> Center Window( );    12. 如何让窗口和 MDI窗口一启动就最大化和最小化?      先说窗口。      在 InitStance 函数中设定 m_nCmdShow的 取值.        m_nCmdShow=SW_SHOWMAXMIZED ;  //最大化        m_nCmdShow=SW_SHOWMINMIZED ;  //最小化        m_nCmdShow=SW_SHOWNORMAL   ;   //正常方式       MDI窗口:         如果是创建新的应用程序,可以用 MFC AppWizard 的Advanced 按钮并在          MDI子窗口风格组中检测最大化或最小化; 还可以重载 MDI Window 的           PreCreateWindow函数,设置WS_MAXMIZE or WS_MINMIZE;        如果从 CMDIChildWnd 派生,调用 OnInitialUpdate函数中的 CWnd::Show       Window来指定 MDI Child Window的 风格。  13. 如何使程序保持极小状态?      很有意思的 问题       这么办: 在恢复程序窗体大小时, Windows会发送WM_QUERY-OPEN消息,       用 ClassWizard设置成员函数 OnQueryOpen() ,add following code:           Bool CMainFrame:: OnQueryOpen( )             {                Return false;             }  14. 如何限制窗口的 大小?     也就是 FixedDialog形式。  Windows 发送 WM_GETMAXMININFO消息来跟踪,   响应它,在 OnGetMAXMININFO 中写代码:  15.  如何使窗口不可见?   很简单,用SW_HIDE 隐藏窗口,可以结合 FindWindow,ShowWindow 控制.  16. 如何使窗口始终在最前方?     两种途径.      BringWindowToTop(Handle);      SetWindowPos函数,指定窗口的 最顶风格,用WS_EX_TOPMOST扩展窗口的 风格            Example:        void  ToggleTopMost( CWnd *pWnd)         {            ASSERT_VALID(pWnd);            pWnd ->SetWindowPos(pWnd-> GetStyle( ) &WS_EX_TOPMOST)?             &wndNoTopMOST: &wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE);          } 17、如何创建一个字回绕的CEditView   重载CWnd : : PreCreateWindow和修改CREATESTRUCT结构,关闭CEditView对象 的ES_AUTOHSCROLL和WS_HSCROLL风格位, 由于CEditView : : PreCreateWindow显示 设置cs. style,调用基类函数后要修改cs . style。 BOOL CSampleEDitView : : PreCreateWindow (CREATESTRUCT&cs) {   //First call basse class function .   BOOL bResutl =CEditView : : PreCreateWindow (cs) ;   // Now specify the new window style .   cs.style &= ~ (ES_AUTOHSCROLL |WS_HSCROLL);   return bResult ; } 18、通用控件的显示窗口   MFC提供了几个CView派生的视窗类, 封装了通用控件的功能,但仍然使用工 作框文档显示窗口体系结构:CEditView封装了编辑控件,CTreeView保持了树列表 控件,CListView封装了列表显示窗口控件,CRichEditView可以处理多种编辑控件。 19、移动窗口   调用CWnd : : SetWindowPos并指定SWP_NOSIZE标志。目的位置与父窗口 有关(顶层窗口与屏幕有关)。调用CWnd : : MoveWindow时必须要指定窗口 的大小。 //Move window to positoin 100 , 100 of its parent window . SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE |SWP_NOAORDER); 20、重置窗口的大小   调用CWnd: : SetWindowPos并指定SWP_NOMOVE标志, 也可调用 CWnd : : MoveWindow 但必须指定窗口的位置。 // Get the size of the window . Crect reWindow ; GetWindowRect (reWindow ); //Make the window twice as wide and twice as tall . SetWindowPos (NULL , 0 , 0 , reWindow . Width ( ) *2,             reWindow . Height () * 2,    SWP_NOMOVE |SWP_NOZORDER ); 21、如何单击除了窗口标题栏以外的区域使窗口移动  当窗口需要确定鼠标位置时Windows向窗口发送WM_NCHITTEST信息,可以处理 该信息使Windows认为鼠标在窗口标题上。对于对话框和基于对话的应用程序,可 以使用ClassWizard处理该信息并调用基类函数, 如果函数返回HTCLIENT 则表明 鼠标在客房区域,返回HTCAPTION表明鼠标在Windows的标题栏中。 UINT CSampleDialog : : OnNcHitTest  (Cpoint point ) {   UINT nHitTest =Cdialog: : OnNcHitTest (point );   return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest ; }   上述技术有两点不利之处, 其一是在窗口的客户区域双击时, 窗口将极大; 其二, 它不适合包含几个视窗的主框窗口。还有一种方法,当用户按下鼠标左键 使主框窗口认为鼠标在其窗口标题上,使用ClassWizard在视窗中处理WM_LBUTTODOWN 信息并向主框窗口发送一个WM_NCLBUTTONDOWN信息和一个单击测试HTCAPTION。 void CSampleView : : OnLButtonDown  (UINT nFlags , Cpoint point ) {   CView : : OnLButtonDow  (nFlags , pont );   //Fool frame window into thinking somene clicked on   its caption bar .   GetParentFrame ( ) —> PostMessage (        WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (poitn .x , point .y) ); }   该技术也适用于对话框和基于对的应用程序,只是不必调用CWnd : : GetParentFrame 。 void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point ) {   Cdialog : : OnLButtonDow (nFlags, goint );   //Fool dialog into thinking simeone clicked on its caption bar . PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x , point. y ) )       } 22、如何改变视窗的背景颜色   Windows向窗口发送一个WM_ERASEBKGND消息通知该窗口擦除背景,可以使用 ClassWizard重载该消息的缺省处理程序来擦除背景(实际是画),并返回TRUE以 防止Windows擦除窗口。 //Paint area that needs to be erased. BOOL CSampleView : : OnEraseBkgnd (CDC* pDC) { // Create a pruple brush. CBrush Brush (RGB (128 , 0 , 128) ); // Select the brush into the device context . CBrush* pOldBrush = pDC—>SelcetObject (&brush); // Get the area that needs to be erased . CRect reClip ; pDC—>GetCilpBox (&rcClip); //Paint the area. pDC—> PatBlt (rcClip.left , rcClip.top ,       rcClip.Width ( ) , rcClip.Height ( ) , PATCOPY ); //Unselect brush out of device context . pDC—>SelectObject (pOldBrush ); // Return nonzero to half fruther processing . return TRUE; } 23、如何改变窗口标题   调用CWnd : : SetWindowText可以改变任何窗口(包括控件)的标题。 //Set title for application's main frame window . AfxGetMainWnd ( ) —> SetWindowText (_T("Application title") ); //Set title for View's MDI child frame window . GetParentFrame ( ) —> SetWindowText ("_T ("MDI Child Frame new title") ); //Set title for dialog's push button control. GetDigitem  (IDC_BUTTON) —> SetWindowText  (_T ("Button new title ") );   如果需要经常修改窗口的标题(注:控件也是窗口),应该考虑使用半文档化 的函数AfxSetWindowText。该函数在AFXPRIV.H中说明,在WINUTIL.CPP中实现,在 联机帮助中找不到它,它在AFXPRIV.H中半文档化, 在以后发行的MFC中将文档化。 AfxSetWindowText的实现如下: voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew ) {   itn nNewLen= Istrlen (Ipaznew);   TCHAR szOld [256];   //fast check to see if text really changes (reduces flash in the controls )   if (nNewLen >_contof (szOld) ||       : : GetWindowText (hWndCrtl , szOld , _countof (szOld) !=nNewLen ||       Istrcmp (szOld , IpszNew )! = 0 {   //change it        : : SetWindowText (hWndCtrl , IpszNew );   } }   24、如何防止主框窗口在其说明中显示活动的文档名   创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位, 如果不希望在 说明中自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard重置 CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。 BOOL CMainFrame : : PreCreateWindow  (CREATESTRUCT&cs) {   //Turn off  FWS_ADDTOTITLE in main frame .   cs.styel & = ~FWS_ADDTOTITLE ;    return CMDIFrameWnd : : PreCreateWindow (cs ); }   关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口,可以调 用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。 25、如何获取有关窗口正在处理的当前消息的信息   调用CWnd: : GetCurrentMessage可以获取一个MSG指针。例如,可以使用 ClassWizard将几个菜单项处理程序映射到一个函数中,然后调用GetCurrentMessage 来确定所选中的菜单项。 viod CMainFrame : : OnCommmonMenuHandler ( ) {   //Display selected menu item in debug window .   TRACE ("Menu item %u was selected . /n" ,                                GetCruuentMessage ( ) —> wParam ); } 26、如何创建一个不规则形状的窗口      可以使用新的SDK函数SetWindowRgn。该函数将绘画和鼠标消息限定在窗口的一 个指定的区域,实际上使窗口成为指定的不规则形状。   使用AppWizard创建一个基于对的应用程序并使用资源编辑器从主对话资源中删 除所在的缺省控件、标题以及边界。   给对话类增加一个CRgn数据成员,以后要使用该数据成员建立窗口区域。     Class CRoundDlg : public CDialog {   … private :   Crgn m_rgn : // window region   … } ;   修改OnInitDialog函数建立一个椭圆区域并调用SetWindowRgn将该区域分配给 窗口: BOOL CRoundDlg : : OnInitDialog ( ) {   CDialog : : OnInitDialog ( ) ;   //Get size of dialog .   CRect rcDialog ;   GetClientRect (rcDialog );   // Create region and assign to window .   m_rgn . CreateEllipticRgn  (0 , 0 , rcDialog.Width ( ) , rcDialog .Height ( ) );   SetWindowRgn (GetSafeHwnd ( ) , (HRGN) m_ rgn , TRUE );   return TRUE ; }   通过建立区域和调用SetWindowRgn,已经建立一个不规则形状的窗口,下面的例 子程序是修改OnPaint函数使窗口形状看起来象一个球形体。 voik CRoundDlg : : OnPaint ( ) {   CPaintDC de (this) ; // device context for painting .   //draw ellipse with out any border   dc. SelecStockObject (NULL_PEN);   //get the RGB colour components of the sphere color   COLORREF color= RGB( 0 , 0 , 255);   BYTE byRed =GetRvalues (color);   BYTE byGreen = GetGvalues (color);   BYTE byBlue = GetBvalues (color);   // get the size of the view window   Crect rect ;   GetClientRect  (rect);       // get minimun number of units   int nUnits =min (rect.right , rect.bottom );         //calculate he horiaontal and vertical step size   float fltStepHorz = (float) rect.right /nUnits ;   float fltStepVert = (float) rect.bottom /nUnits ;   int nEllipse = nUnits/3; // calculate how many to draw   int nIndex ;             // current ellipse that is being draw   CBrush brush ;       // bursh used for ellipse fill color   CBrush *pBrushOld;     // previous brush that was selected into dc   //draw ellipse , gradually moving towards upper-right corner   for (nIndex = 0 ; nIndes < + nEllipse ; nIndes ++) {   //creat solid brush   brush . CreatSolidBrush   (RGB ( ( (nIndex *byRed ) /nEllipse ).              ( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue) /nEllipse ) ) );   //select brush into dc   pBrushOld= dc .SelectObject (&brhsh);   //draw ellipse   dc .Ellipse (  (int) fltStepHorz * 2, (int) fltStepVert * nIndex ,        rect. right -( (int) fltStepHorz * nIndex )+ 1,        rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1) ;   //delete the brush   brush.DelecteObject ( );   }   }     最后,处理WM_NCHITTEST消息,使当击打窗口的任何位置时能移动窗口。 UINT CRoundDlg : : OnNchitTest (Cpoint point ) {   //Let user move window by clickign anywhere on the window .   UINT nHitTest = CDialog : : OnNcHitTest (point) ;   rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest ;   } 27、如何在代码中获取工具条和状态条的指针   缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条 有一个AFX_IDW_STATUS_BAR标识符,工具条有一个AFX_IDW_TOOLBAR标识符,下例说 明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些 子窗口的指针: //Get pointer to status bar . CStatusBar * pStatusBar =   (CStatusBar *) AfxGetMainWnd ( ) —> GetDescendantWindow (AFX_IDW_STUTUS_BAR); //Get pointer to toolbar . CToolBar * pToolBar =   (CToolBar * ) AfxGetMainWnd ( ) —> GetDescendantWindow (AFX_IDW_TOOLBAR); 28、如何使能和禁止工具条的工具提示   如果设置了CBRS_TOOLTIPS风格位,工具条将显示工具提示,要使能或者禁止 工具提示,需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle 和CControlBar : : SetBarStyle建立一个完成此功能的成员函数: void CMainFrame : : EnableToolTips ( BOOL bDisplayTips ) {   ASSERT_VALID  (m_wndToolBar);   DWORD dwStyle = m _wndToolBar.GetBarStyle ( ) ;   if (bDisplayTips)        dwStyle |=CBRS_TOOLTIPS ;   else        dwStyle & = ~ CBRS_TOOLTIPS ;   m_wndToolBar.SetBarStyle  (dwStyle ); } 29、如何设置工具条标题   工具条是一个窗口,所以可以在调用CWnd : : SetWindowText来设置标题, 例子如下: int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct ) {        …   // Set the caption of the toolbar .   m_wndToolBar.SetWindowText  (_T "Standdard"); 30、如何创建和使用无模式对话框   MFC将模式和无模式对话封装在同一个类中,但是使用无模式对话需要几 个对话需要几个额处的步骤。首先,使用资源编辑器建立对话资源并使用 ClassWizard创建一个CDialog的派生类。模式和无模式对话的中止是不一样的: 模式对话通过调用CDialog : : EndDialog 来中止,无模式对话则是调用 CWnd: : DestroyWindow来中止的,函数CDialog : : OnOK和CDialog : : OnCancel 调用EndDialog ,所以需要调用DestroyWindow并重置无模式对话的函数。 void CSampleDialog : : OnOK ( ) {   // Retrieve and validate dialog data .   if (! UpdateData (TRUE) )   {       // the UpdateData rountine will set focus to correct item       TRACEO (" UpdateData failed during dialog termination ./n") ;       return ;   }       //Call DestroyWindow instead of EndDialog .   DestroyWindow ( ) ; } void CSampleDialog : : OnCancel ( ) {   //Call DestroyWindow instead of EndDialog .   DestroyWindow ( ) ; }   其次,需要正确删除表示对话的C++对象。对于模式对来说,这很容易,需要创 建函数返回后即可删除C++对象;无模式对话不是同步的,创建函数调用后立即返回, 因而用户不知道何时删除C++对象。撤销窗口时工作框调用CWnd : : PostNcDestroy, 可以重置该函数并执行清除操作,诸如删除this指针。 void CSampleDialog : : PostNcDestroy ( ) {   // Declete the C++ object that represents this dialog .   delete this ; }   最后,要创建无模式对话。可以调用CDialog : : DoModal创建一个模式对放, 要创建一个无模式对话则要调用CDialog: : Create。下面的例子说明 了应用程序 是如何创建无模式对话的: void CMainFrame : : OnSampleDialog  ( ) {   //Allocate a modeless dialog object .   CSampleDilog * pDialog =new CSampleDialog ;   ASSERT_VALID (pDialog) ;   //Create the modeless dialog .   BOOL bResult = pDialog —> Creste (IDD_IDALOG) ;   ASSERT (bResult ) ; } 31、如何在对话框中显示一个位图   这要归功于Win 32先进的静态控件和Microsoft的资源编辑器, 在对话框中 显示位图是很容易的, 只需将图形控件拖到对话中并选择适当属性即可,用户也 可以显示图标、位图以及增强型元文件。 32、如何改变对话或窗体视窗的背景颜色   调用CWinApp : : SetDialogBkColor可以改变所有应用程序的背景颜色。第 一个参数指定了背景颜色,第二个参数指定了文本颜色。下例将应用程序对话设置 为蓝色背景和黄色文本。 BOOL CSampleApp : : InitInstance  ( ) {       …   //use blue dialog with yellow text .   SetDialogBkColor (RGB (0, 0, 255 ), RGB ( 255 , 255 , 0 ) ) ;       … }   需要重画对话(或对话的子控件)时,Windows向对话发送消息WM_CTLCOLOR, 通常用户可以让Windows选择绘画背景的刷子,也可重置该消息指定刷子。下例说 明了创建一个红色背景对话的步骤。   首先,给对话基类增加一人成员变量CBursh : class CMyformView : public CformView {   …   private :       CBrush m_ brush ; // background brush   … } ;   其次, 在类的构造函数中将刷子初始化为所需要的背景颜色。 CMyformView : : CMyformView ( ) {   // Initialize background brush .   m_brush .CreateSolidBrush  (RGB ( 0, 0, 255 ) ) }   最后,使用ClassWizard处理WM_CTLCOLOR消息并返回一个用来绘画对话背景的 刷子句柄。注意:由于当重画对话控件时也要调用该函数,所以要检测nCtlColor 参量。 HBRUSH CMyformView : : OnCtlColor (CDC* pDC , CWnd*pWnd , UINT nCtlColor )   {   // Determine if drawing a dialog box . If we are , return +handle to   //our own background brush . Otherwise let windows handle it .   if (nCtlColor = = CTLCOLOR _ DLG )       return (HBRUSH) m_brush .GetSafeHandle ( ) ;   return CformView : : OnCtlColor (pDC, pWnd , nCtlColor ); } 33、如何获取一个对话控件的指针   有两种方法。其一,调用CWnd: : GetDlgItem,获取一个CWnd*指针调用成 员函数。下例调用GetDlgItem,将返回值传给一个CSpinButtonCtrl*以便调用 CSpinButtonCtrl : : SetPos 函数: BOOL CSampleDialog : : OnInitDialog ( ) {   CDialog : : OnInitDialog ( ) ;   //Get pointer to spin button .   CSpinButtonCtrl * pSpin - ( CSpinButtonCtrl *) GetDlgItem (IDC_SPIN) ;   ASSERT _ VALID (pSpin) ;   //Set spin button's default position .   pSpin —> SetPos (10) ;   return TRUE ; }   其二, 可以使用ClassWizard将控件和成员变量联系起来。在ClassWizard中简 单地选择Member Variables标签,然后选择Add Variable …按钮。如果在对话资源 编辑器中,按下Ctrl键并双击控件即可转到Add Member Variable对话。 34、如何禁止和使能控件   控件也是窗口,所以可以调用CWnd : : EnableWindow使能和禁止控件。 //Disable button controls . m_wndOK.EnableWindow (FALSE ) ; m_wndApply.EnableWindow (FALSE ) ; 35、如何改变控件的字体   由于控件是也是窗口,用户可以调用CWnd: : SetFont指定新字体。该函数用 一个Cfont指针,要保证在控件撤消之前不能撤消字体对象。下例将下压按钮的字 体改为8点Arial字体: //Declare font object in class declaration (.H file ). private :   Cfont m_font ; // Set font in class implementation (.Cpp file ). Note m_wndButton is a //member variable added by ClassWizard.DDX routines hook the member //variable to a dialog button contrlo.       BOOL CSampleDialog : : OnInitDialog ( ) {   …   //Create an 8-point Arial font   m_font . CreateFont  (MulDiv (8 , -pDC—> GetDeviceCaps  (LOGPIXELSY) , 72).      0 , 0 , 0 , FW_NORMAL , 0 , 0, 0, ANSI_CHARSER, OUT_STROKE_PRECIS ,      CLIP_STROKE _PRECIS , DRAFT _QUALITY      VARIABLE_PITCH |FF_SWISS, _T ("Arial") );   //Set font for push button .   m_wndButton . SetFont (&m _font );   … } 36、如何在OLE控件中使用OLE_COLOR数据类型   诸如COleControl : : GetFortColor和COleControl : : GetBackColor等函数 返回OLE _COLOR数据类型的颜色,而GDI对象诸如笔和刷子使用的是COLORREF数据类 型,调用COleControl : : TranslateColor可以很容易地将OLE_COLOR类型改为 COLORREF类型。下例创建了一个当前背景颜色的刷子: void CSampleControl : : OnDraw (CDC* pdc   const Crect& rcBounds , const Crect& rcInvalid ) {   //Create a brush of the cuttent background color .   CBrush brushBack (TranslateColor (GetBackColor ( ) ) );   //Paint the background using the current background color .   pdc—> FilllRect  (rcBounds , &brushBack) ;   //other drawign commands   … } 37、在不使用通用文件打开对话的情况下如何显示一个文件列表   调用CWnd: : DlgDirList或者CWnd: : DlgDirListComboBox, Windows 将自动 地向列表框或组合框填充可用的驱动器名或者指定目录中的文件,下例将Windows目 录中的文件填充在组合框中: BOOL CSampleDig : : OnInitDialog ( ) {   CDialog : : OnInitDialog  ( )   TCHAR szPath [MAX_PATH] = {"c://windows"} ;   int nReslt = DlgDirListComboBox  (szPath , IDC_COMBO , IDC_CURIDIR,       DDL_READWRITE |DDL_READONLY|DDL_HIDDEN|       DDL_SYSTEM|DDL_ARCHIVE ) ;   return TRUE ; } 38、为什么旋转按钮控件看起来倒转   需要调用CSpinCtrl : : SetRange 设置旋转按钮控件的范围,旋转按钮控件 的缺省上限为0,缺省下限为100,这意味着增加时旋转按控件的值由100变为0。 下例将旋转按钮控件的范围设置为0到100: BOOL CAboutDlg : : OnInitDialog ( ) {   CDialog : : OnInitDialog ( )       //set the lower and upper limit of the spin button   m_wndSpin . SetRange ( 0 ,100 ) ;     return TRUE ; }   Visual C++ 4.0 Print对话中的Copise旋转按钮控件也有同样的问题:按下Up 按钮时拷贝的数目减少,而按下Down 按钮时拷贝的数目增加。 39为什么旋转按钮控件不能自动地更新它下面的编辑控件   如果使用旋转按钮的autu buddy特性, 则必须保证在对话的标记顺序中 buddy窗口优先于旋转按钮控件。从Layout菜单中选择Tab Order菜单项(或者按 下Crtl+D)可以设置对话的标签顺序。 40、如何用位图显示下压按钮   Windows 95按钮有几处新的创建风格,尤其是BS_BITMAP和BS_ICON,要想具 有位图按钮,创建按钮和调用CButton : : SetBitmap或CButton : : SetIcon时 要指定BS_BITMAP或BS_ICON风格。   首先,设置按钮的图标属性。   然后,当对话初始化时调用CButton: : SetIcon。注意:下例用图标代替位 图,使用位图时要小心,因为不知道背景所有的颜色——并非每个人都使用浅灰 色。 BOOL CSampleDlg : : OnInitDialog ( )         { CDialog : : OnInitDialog ( ) ; //set the images for the push buttons . m_wndButton1.SetIcon (AfxGetApp  ( ) —> LoadIcon (IDI _ IPTION1) ) m_wndButton2.SetIcon (AfxGetApp  ( ) —> LoadIcon (IDI _ IPTION2) ) m_wndButton3.SetIcon (AfxGetApp  ( ) —> LoadIcon (IDI _ IPTION3) )   return TRUE ; } 41、如何一个创建三态下压按钮   可以使用新的BS_PUSHBUTTON 风格位和检测框以及按钮来创建一个三态下 压按钮。这很容易,只需将检测框和按钮拖拉到对话中并指定属性Push—like即 可。不用任何附加程序就可以成为三态下压按钮。 42、如何动态创建控件   分配一个控件对象的实例并调用其Create成员函数。开发者最容易忽略两件 事:忘记指定WS_VISBLE标签和在栈中分配控件对象。下例动态地创建一个下压按 钮控件: //In class declaration (.H file ). private :   CButton* m _pButton ; //In class implementation (.cpp file ) . m_pButton =new CButton ; ASSERT_VALID   (m_pButton); m_pButton —>Create (_T ("Button Title ") , WS_CHILD |WS_VISIBLE |BS_PUSHBUTTON.   Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON ) 43、如何限制编辑框中的准许字符   如果用户在编辑控件中只允许接收数字,可以使用一个标准的编辑控件并指 定新的创建标志ES_NUMBERS,它是Windows 95新增加的标志,该标志限制 编辑控 件只按收数字字符。如果用户需要复杂的编辑控件,可以使用Microsoft 的屏蔽 编辑控件,它是一个很有用的OLE定制控件。   如果希望不使用OLE 定制控件自己处理字符,可以派生一个CEdit 类并处理 WM_CHAR消息,然后从编辑控件中过滤出特定的字符。首先,使用ClassWizard 建 立一个 CEdit的派生类,其次,在对话类中指定一个成员变量将编辑控件分类在 OnInitdialog 中调用CWnd: : SubclassDlgItem . //In your dialog class declaration (.H file ) private :   CMyEdit m_wndEdit ; // Instance of your new edit control . //In you dialog class implementation (.CPP file ) BOOL CSampleDialog : : OnInitDialog ( ) {   …   //Subclass the edit lontrod .   m_wndEdit .SubclassDlgItem  (IDC_EDIT,this );   … }   使用ClassWizard处理WM_CHAR消息,计算nChar参量并决定所执行的操作,用 户可以确定是否修改、传送字符。下例说明了如何显示字母字符,如果字符是字母 字符,则调用CWnd ; OnChar,否则不调用OnChar. //Only display alphabetic dharacters . void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags ) {   //Determine if nChar is an alphabetic character .   if (: : IsCharAlpha  ( ( TCHAR) nChar ) )       CEdit : : OnChar (nChar, nRepCnt , nFlags ); }   如果要修改字符,则不能仅仅简单地用修改过的nChar调用CEdit : : OnChar, 然后CEdit: : OnChar调用CWnd: : Default获取原来的wParam 和lParam 的值 ,这 样是不行的。要修改一个字符,需要首先修改nChar,然后用修改过的nChar调用 CWnd: : DefWindowProc。下例说明了如何将字符转变为大写: //Make all characters uppercase void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags ) {   //Make sure character is uppercase .   if (: : IsCharAlpha  ( .( TCHAR) nChar)        nChar=: : CharUpper (nChar ) ;   //Bypass default OnChar processing and directly call   //default window proc.   DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt , nFlags )) ; } 44、如何改变控件的颜色   有两种方法。其一,可以在父类中指定控件的颜色,或者利用MFC4.0新的消息反 射在控件类中指定颜色。   当控件需要重新着色时,工作框调用父窗口(通常是对话框)的 CWnd: : OnCrtlColor,可以在父窗口类中重置该函数并指定控件的新的绘画属 性。例如,下述代码将对话中的所有编辑控件文本颜色改为红色: HBRUSH CAboutDig : : OnCtlColor (CDC * pDCM , CWnd * pWnd , UINT nCtlColor) {   HBRUSH hbr = CDialog : : OnCtlColor (pDC, pWnd , nCtlColor );   //Draw red text for all edit controls .   if (nCtlColor= = CTLCOLOR_EDIT )      pDC —> SetTextColor (RGB (255 , 0 , 0 , ) ) ;   return hbr ; }   然而,由于每个父窗口必须处理通知消息并指定每个控件的绘画属性,所以, 这种方法不是完全的面向对象的方法。控件处理该消息并指定绘画属性更合情合理。   消息反射允许用户这样做。通知消息首先发送给父窗口,如果父窗口没有处理 则发送给控件。创建一个定制彩色列表框控件必须遵循下述步骤。   首先,使用ClassWizard 创建一个CListBox 的派生类并为该类添加下述数据 成员。 class CMyListBox ; publilc CListBox { … private;   COLORREF m_clrFor ;     // foreground color   COLORREF m_clrBack ;   //background color   Cbrush m_brush ;         //background brush … } ;   其次,在类的构造函数中,初始化数据中。 CMyListBox : : CMyListBox () {   //Initialize data members .   m_clrFore =RGB (255 , 255 , 0) ;   // yellow text   m_clrBack=RGB (0 , 0 , 255) ;    // blue background   m_brush . CreateSolidBrush  (m _clrBack ); }   最后,使用ClassWizard处理反射的WM_CTLCOLOR(=WM_CTLCOLOR)消息并指定新 的绘画属性。 HBRUSH CMyListBox : : CtlColor (CDC* pDC, UINT nCtlColor ) {   pDC—>SetTextColor (m_clrFore);   pDC—>SetBkColor  (m_clrBack);               return (HBRUSH) m_brush.GetSafeHandle () }   现在,控件可以自己决定如何绘画,与父窗口无关。 45、当向列表框中添加多个项时如何防止闪烁   调用CWnd::SetRedraw 清除重画标志可以禁止CListBox(或者窗口)重画。 当向列表框添加几个项时,用户可以清除重画标志,然后添加项,最后恢复重画 标志。为确保重画列表框的新项,调用SetRedraw (TRUE) 之后调用CWnd::Invalidate。 //Disable redrawing. pListBox->SetRedraw (FALSE); //Fill in the list box gere //Enable drwing and make sure list box is redrawn. pListBox->SetRedraw (TRUE); pListBox->Invalidate (); 46、如何向编辑控件中添加文本   由于没有CEdit:: AppendText函数,用户只好自己做此项工作。调用 CEdit:: SetSel移动到编辑控件末尾,然后调用CEdit:: ReplaceSel添加文 本。下例是AppendText 的一种实现方法: void CMyEdit:: AppendText (LPCSTR pText) {    int nLen=GetWindowTextLength ();    SetFocus ();    SetSel (nLen, nLen);    ReplaceSel (pText); } 47、如何访问预定义的GDI对象   可以通过调用CDC:: SlectStockObject使用Windows的几个预定义的对象,诸 如刷子、笔以及字体。下例使用了Windows预定义的笔和刷子GDI对象在视窗中画一 个椭圆。 //Draw ellipse using stock black pen and gray brush. void CSampleView:: OnDraw (CDC* pDC) {    //Determine size of view.    CRect rcView;    GetClientRect (rcView);    //Use stock black pen and stock gray brush to draw ellipse.    pDC->SelectStockObject (BLACK_PEN);    pDC->SelectStockObject (GRAY_BRUSH)    //Draw the ellipse.    pDC->Ellipse (reView); }   也可以调用新的SDK函数GetSysColorBrush获取一个系统颜色刷子,下例用背景 色在视窗中画一个椭圆: void CsampleView:: OnDraw (CDC* pDC) {    //Determine size of view.    CRect rcView;    GetClientRect (rcView);    //Use background color for tooltips brush.    CBrush * pOrgBrush=pDC->SelectObject (         CBrush::FromHandle (::GetSysColorBrush (COLOR_INFOBK)));    //Draw the ellipse.    pDC->Ellipse (rcView);    //Restore original brush.    pDC->SelectObject (pOrgBrush); } 48、如何获取GDI对象的属性信息     可以调用GDIObject:: GetObject。这个函数将指定图表设备的消息写入到 缓冲区。下例创建了几个有用的辅助函数。 //Determine if font is bold. BOOL IsFontBold (const CFont&font) {    LOGFONT stFont;    font.GetObject (sizeof (LOGFONT), &stFont);    return (stFont.lfBold)? TRUE: FALSE; } //Return the size of a bitmap. CSize GetBitmapSize (const CBitmap&bitmap) {    BITMAP stBitmap;    bitmap.GetObject (sizeof (BITMAP), &stBitmap);    return CSize (stBitmap.bmWidth, stBitmap. bmHeight); } //Create a pen with the same color as a brush. BOOL CreatePenFromBrush (Cpen&pen, cost Cbrush&brush) {    LOGBRUSH stBrush;    brush.Getobject (sizeof (LOGBRUSH), &stBrush);    return pen. Createpen (PS_SOLID, 0, stBrush.ibColor); } 49、如何实现一个橡皮区矩形   CRectTracker是一个很有用的类,可以通过调用CRectTracker:: TrackRubberBand 响应WM_LBUTTONDOWN消息来创建一个橡皮区矩形。下例表明使用CRectTracker移动 和重置视窗中的蓝色椭圆的大小是很容易的事情。   首先,在文件档中声明一个CRectTracker数据成员: class CSampleView : Public CView {   …   public :        CrectTracker m_tracker;   … };   其次,在文档类的构造函数中初始化CRectTracker 对象: CSampleDoc:: CSampleDOC () {    //Initialize tracker position, size and style.    m_tracker.m_rect.SetRect (0, 0, 10, 10);    m_tracker.m_nStyle=CRectTracker:: resizeInside  |          CRectTracker:: dottedLine; }   然后,在OnDraw函数中画椭圆和踪迹矩形: void CSampleView:: OnDraw (CDC* pDC) {    CSampleDoc* pDoc=GetDocument ();    ASSERT_VALID (pDoc);    //Select blue brush into device context.    CBrush brush (RGB (0, 0, 255));    CBrush* pOldBrush=pDC->SelectObject (&brush);      //draw ellipse in tracking rectangle.    Crect rcEllipse;    pDoc->m_tracker.GetTrueRect (rcEllipse);    pDC->Ellipse (rcEllipse);    //Draw tracking rectangle.    pDoc->m_tracker.Draw (pDC);    //Select blue brush out of device context.    pDC->Selectobject (pOldBrush); }   最后,使用ClassWizard处理WM_LBUTTONDOWN消息,并增加下述代码。该段代码 根据鼠标击键情况可以拖放、移动或者重置椭圆的大小。 void CSampleView::OnLButtonDown (UINT nFlags, CPoint point) {    //Get pointer to document.    CSampleDoc* pDoc=GetDocument ();    ASSERT_VALID (pDoc);    //If clicked on ellipse, drag or resize it. Otherwise create a    //rubber-band rectangle nd create a new ellipse.    BOOL bResult=pDoc->m_tracker.HitTest (point)!=        CRectTracker::hitNothing;    //Tracker rectangle changed so update views.    if (bResult)    {       pDoc->m_tracker.Track (this,point,TRue);       pDoc->SetModifiedFlag ();       pDoc->UpdateAllViews (NULL);    }        else       pDoc->m-tracker.TrackRubberBand (this,point,TRUE);    CView:: onLButtonDown (nFlags,point); } 50、如何更新翻转背景颜色的文本   调用CDC:: SetBkmode并传送OPAQUE用当前的背景颜色填充背景,或者调用 CDC::SetBkMode并传送TRANSPAARENT使背景保持不变,这两种方法都可以设置背景 模式。下例设置背景模式为TRANSPARENT,可以两次更新串,用花色带黑阴影更新 文本。黑色串在红色串之后,但由于设置了背景模式仍然可见。 void CSampleView:: OnDraw (CDC* pDC) {    //Determint size of view.    CRect rcView;    GetClientRect (rcVieew);    //Create sample string to display.    CString str (_T ("Awesome Shadow Text..."));    //Set the background mode to transparent.    pDC->SetBKMode (TRANSPARENT);    //Draw black shadow text.    rcView.OffsetRect  (1, 1);    pDc->SetTextColor (RGB (0, 0, 0));    pDC->DrawText (str, str.GetLength (), rcView,        DT_SINGLELINE | DT_CENTER | DT_VCENTER);     //Draw red  text.    rcView.OffsetRect  (-1,-1);    pDc->SetTextColor (RGB (255, 0, 0));    pDC->DrawText (str, str.GetLength (), rcView,        DT_SINGLELINE | DT_CENTER | DT_VCENTER); } 51、如何创建一个具有特定点大小的字体   可以指定字体逻辑单位的大小,但有时指定字体的点的大小可能会更方便一 些。可以如下将字体的点转换为字体的高度: int nHeigth=mulDiv (nPointSize, -dc.GetDeviceCaps (LOGPIXELSY), 72);   下例创建了一个8点的Apial字体: … CClientDC dc (AqfxGetMainWnd ()); m_font. CreateFont (MulDiv (8, -dc.GetDeviceCaps (LOGPIXELSY),       72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,       OUT_STROKE_PRECIS,CLIP_STROKE_PRECIS,DRAFT_QUALITY,       VARIABLE_PITCH | FF-SWISS,_T ("Arial")); ... 52、如何计算一个串的大小   函数CDC:: Det text Extent 根据当前选择的字体计算一个串的高度和宽 度。如果使用的不是系统字体而是其他字体,则在调用GetTextExtent之前将字 体选进设备上下文中是很重要的,否则计算高度和宽度时将依据系统字体,由此 得出的结果当然是不正确的。下述样板程序当改变下压按钮的标题时动态调整按 钮的大小,按钮的大小由按钮的字体和标题的大小而定。响应消息WM_SETTEXT时 调用OnSetText,该消息使用ON_MESSAE宏指令定义的用户自定义消息。 LRESULT CMyButton:: OnSettext (WPARAM wParam, LPARAM lParam) {    //Pass message to window procedure.    LRESULT bResult=CallWindowProc (*GetSuperWndProcAddr (),        m_hWnd, GetCurrentMessage () ->message,wParam,lParam);    //Get title of push button.    CString strTitle;    GetWindowText (strTitle);    //Select current font into device context.    CDC* pDC=GetDc ();    CFont*pFont=GetFont ();    CFont*pOldFont=pDC->SelectObject (pFont);    //Calculate size of title.    CSize size=pDC->GetTextExent (strTitle,strTitle.GetLength ());    //Adjust the button's size based on its title.    //Add a 5-pixel border around the button.    SetWindowPos (NULL, 0, 0, size.cx+10, size.cy+10,        SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);    //Clean up.    pDC->SelectFont (pOldFont);    ReleaseDC (pDC);    return bResult; } 53、如何显示旋转文本   只要用户使用TrueType或者GDI笔或字体就可以显示旋转文本(有些硬件设备也 支持旋转光栅字体)。LOGFONT结构中的ifEscapement成员指定了文本行和x轴的角 度,角度的单位是十分之一度而不是度,例如,ifEscapement为450表示字体旋转 45度。为确保所有的字体沿坐标系统的同一方向旋转,一定要设置ifEscapement成 员的CLIP_LH_ANGLES位,否则,有些字体可能反向旋转。下例使用了14点Arial字体 每间隔15度画一个串。 void CSampleView:: OnDraw (CDC* pDC) {    //Determine the size of the window.    CRect rcClient;    GetClientRect (rcClient);    //Create sample string.    CString str (_T ("Wheeee...I am rotating!"));    //Draw transparent, red text.    pDC->SetBkMode (TRANSPARENT);    pDC->SetTextColor (RGB (255,0,0));    CFont font;           //font object    LOGFONT stFont;    //font definition    //Set font attributes that will not change.    memset (&stFont, 0, sizeof (LOGFONT));    stFont.ifheight=MulDiv (14, -pDC->GetDeviceCaps (LOGPIXELSY), 72);    stFont.ifWeight=FW_NORMAL;    stFont.ifClipPrecision=LCIP_LH_ANGLES;    strcpy (stFont.lfFaceName, "Arial");    //Draw text at 15degree intervals.    for (int nAngle=0; nAngle<3600; nAngle+=150) {        //Specify new angle.        stFont.lfEscapement=nAngle;        //Create and select font into dc.        font.CreateFontIndirect (&stfont);        CFont* pOldFont=pDC->SelectObject (&font);        //Draw the text.        pDC->SelectObject (pOldFont);        font.DelectObjext ();    } } 54、如何正确显示包含标签字符的串     调用GDI文本绘画函数时需要展开标签字符,这可以通过调用 CDC:: TabbedTextOut或者CDC:: DrawText并指定DT_EXPANDTABS标志来完 成。TabbedTextOut函数允许指定标签位的数组,下例指定每20设备单位展 开一个标签: void CSampleView:: OnDraw (CDC* pDC) {    CTestDoc* pDoc=GetDocument ();    ASSERT_VALID (pDoC);    CString str;    str.format (_T ("Cathy/tNorman/tOliver"));    int nTabStop=20; //tabs are every 20 pixels    pDC->TabbedtextOut (10, 10, str, 1, &nTabStop, 10); } 55、串太长时如何在其末尾显示一个省略号   调用CDC:: DrawText并指定DT_END_ELLIPSIS标志,这样就可以用小略号取 代串末尾的字符使其适合于指定的边界矩形。如果要显示路径信息,指定 DT_END_ELLIPSIS标志并省略号取代串中间的字符。 void CSampleView:: OnDraw (CDC* pDC) {    CTestDoc* pDoc=GetDocument ();    ASSERT_VALID (pDoc);    //Add ellpsis to end of string if it does not fit    pDC->Drawtext (CString ("This is a long string"),        CRect (10, 10, 80, 30), DT_LEFT | DT_END_ELLIPSIS);    //Add ellpsis to middle of string if it does not fit    pDC->DrawText (AfxgetApp () ->m_pszhelpfilePath,        CRect (10, 40, 200, 60), DT_LEFT | DT_PATH_ELLIPSIS);     } 56、如何快速地格式化一个CString对象   调用CString:: format,该函数和printf函数具有相同的参数,下例说明了 如何使用format函数: //Get size of window. CRect rcWindow; GetWindowRect (rcWindow); //format message string. CString strMessage; strMessage.format (_T ("Window Size (%d, %d)"),               rcWindow.Width (), rcWindow.Height ()); //Display the message. MessageBox (strmessage); 57、为什么即使调用EnableMenuItem菜单项后,菜单项还处于禁止状态   需要将CFrameWnd:: m_bAutomenuEnable设置为FALSE,如果该数据成员 为TRUE(缺省值),工作框将自动地禁止没有ON_UPDATE_COMMAND_UI或者 ON_COMMAND的菜单项。 //Disable MFC from automatically disabling menu items. m_bAuoMenuEnable=FALSE; //Now enable the menu item. CMenu* pMenu=GetMenu (); ASSERT_VALID (pMenu); pMenu->EnableMenuItem (ID_MENU_ITEM,MF_BYCOMMAND | MF_ENABLED); 58、如何给系统菜单添加一个菜单项   给系统菜单添加一个菜单项需要进行下述三个步骤:   首先,使用Resource Symbols对话(在View菜单中选择Resource Symbols... 可以显示该对话)定义菜单项ID,该ID应大于0x0F而小于0xF000;   其次,调用CWnd::GetSystemMenu获取系统菜单的指针并调用 CWnd:: Appendmenu将菜单项添加到菜单中。下例给系统菜单添加两个新的 菜单项: int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct) {    …    //Make sure system menu item is in the right range.    ASSERT  (IDM_MYSYSITEM &0xFFF0)==IDM_MYSYSITEM);   ASSERT (IDM-MYSYSITEM<0xF000);    //Get pointer to system menu.    CMenu* pSysmenu=GetSystemmenu (FALSE);    ASSERT_VALID (pSysMenu);    //Add a separator and our menu item to system menu.    CString StrMenuItem (_T ("New menu item"));    pSysMenu->Appendmenu (MF_SEPARATOR);    pSysMenu->AppendMenu (MF_STRING, IDM_MYSYSITEM, strMenuitem);    … }   现在,选择系统菜单项时用户应进行检测。使用ClassWizard处理 WM_SYSCOMMAND消息并检测用户菜单的nID参数: void CMainFrame:: OnSysCommand (UINT nID,LPARAM lParam) {    //Determine if our system menu item was selected.    if ( (nID & 0xFFF0)==IDM_MYSYSITEM)    {         //TODO-process system menu item    }      else         CMDIFrameWnd:: OnSysCommand (nID, lParam); }   最后,一个设计良好的UI应用程序应当在系统菜单项加亮时在状态条显示 一个帮助信息,这可以通过增加一个包含系统菜单基ID的串表的入口来实现。 59、如何确定顶层菜单所占据的菜单行数   这可以通过简单的减法和除法来实现。首先,用户需要计算主框窗口的高 度和客户区;其次,从主框窗口的高度中减去客户区、框边界以及标题的高度; 最后,除以菜单栏的高度。下例成员函数是一个计算主框菜单所占据的行数的代 码实现。 int CMainFrame:: GetMenuRows () {    CRect rcFrame,rcClient;    GetWindowRect (rcFrame);    GetClientRect (rcClient);    return (rcFrame.Height () -rcClient.Height ()-          :: GetSystemMetrics (SM_CYCAPTION) -          (:: getSystemMetrics (SM_CYFRAME) *2)) /          :: GetSystemMetrics (SM_CYMENU); } 60、在用户环境中如何确定系统显示元素的颜色   调用SDK函数GetSysColor可以获取一个特定显示元素的颜色。下例说明了如何 在MFC函数CMainFrameWnd:: OnNcPaint中调用该函数设置窗口标题颜色。 void CMiniFrameWnd:: OnNcPaint () {    …    dc.SetTextColor (:: GetSysColor (m_bActive ?        COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));    … } 61、如何查询和设置系统参数   在Windows 3.1 SDK中介绍过SDK函数SystemParametersInfo,调用该函数可 以查询和设置系统参数,诸如按键的重复速率设置、鼠标双击延迟时间、图标字体 以及桌面覆盖位图等等。 //Create a font that is used for icon titles. LOGFONT stFont; :: SystemParametersInfo (SPIF_GETICONTITLELOGFONT,    sizeof (LOGFONT), &stFont, SPIF_SENDWININICHANGE); m_font.CreateFontIndirect (&stFont); //Change the wallpaper to leaves.bmp. :: SystemParametersInfo (SPI_SETDESKWALLPAPER, 0,      _T (" forest.bmp"), SPIF_UPDATEINIFILE); 62、如何使用一个预定义的Windows光标   调用CWinApp:: LoadStandardCursor并传送光标标识符。    BOOL CSampleDialog:: OnSetCursor (CWnd* pWnd, UINT nHitTest, UINT message) {    //Display wait cursor if busy.    if (m_bBusy)    {        SetCursor (AfxGetApp () ->LoadStandardCursor (IDC_WAIT));        return TRUE;    }    return CDialog:: OnSetCursor (pWnd. nHitTest,message); } 63、如何确定当前屏幕分辨率   调用SDK函数GetSystemMetrics,该函数可以检索有关windows显示信息,诸如 标题大小、边界大小以及滚动条大小等等。 //Initialize CSize object with screen size. CSize sizeScreen (GetSystemMetrics (SM_CXSCREEN),    GetSystemMetrics (SM_CYSCREEN)); 64、如何检索原先的Task Manager应用程序使用的任务列表   原先的Task Manager应用程序显示顶层窗口的列表。为了显示该列表,窗口 必须可见、包含一个标题以及不能被其他窗口拥有。调用CWnd:: GetWindow可以 检索顶层窗口的列表,调用IsWindowVisible、GetWindowTextLength以及GetOwner 可以确定窗口是否应该在列表中。下例将把TaskManager窗口的标题填充到列表中。 void GetTadkList (CListBox&list) {    CString strCaption;        //Caption of window.    list.ResetContent ();       //Clear list box.    //Get first Window in window list.    ASSERT_VALID (AfxGetMainWnd ());    CWnd* pWnd=AfxGetMainWnd () ->GetWindow (GW_HWNDFIRST);    //Walk window list.    while (pWnd)    {        // I window visible, has a caption, and does not have an owner?        if (pWnd ->IsWindowVisible () &&           pWnd ->GetWindowTextLength () &&! pWnd ->GetOwner ())        {           //Add caption o window to list box.           pWnd ->GetWindowText  (strCaption);           list.AddString (strCaption);        }        //Get next window in window list.        pWnd=pWnd->GetWindow (GW_HWNDNEXT);    } } 65、如何确定Windows和Windows系统目录   有两个SDK函数可以完成该功能。GetWindowsDirectory和GetSystemDirectory, 下例说明了如何使用这两个函数: TCHAR szDir [MAX_PATH]; //Get the full path of the windows directory. :: GetWindowsDirectory (szDir, MAX_PATH); TRACE ("Windows directory %s/n", szDir); //Get the full path of the windows system directory. :: GetSystemDirectory (szDir, MAX_PATH); TRACE ("Windows system directory %s/n", szDir); 66、在哪儿创建临文件   调用SDK函数GetTemPath可以确定临时文件的目录,该函数首先为临时路径 检测TMP环境变量:如果没有指定TMP,检测TMP环境变量,然后返回到当前目录。 下例说明了如何创建一个临时文件。 …    //get unique temporary file.    CString strFile;    GetUniqueTempName (strFile);    TRY    {       //Create file and write data.Note that file is closed       //in the destructor of the CFile object.       CFile file (strFile,Cfile:: modeCreate | Cfile:: modeWrite);       //write data    }    CATCH (CFileException, e)    {       //error opening file    }    END_CATCH … Void GetuniqueTempName (CString& strTempName) {    //Get the temporary files directory.    TCHAR szTempPath  [MAX_PATH];    DWORD dwResult=:: GetTempPath (MAX_PATH, szTempPath);    ASSERT (dwResult);    //Create a unique temporary file.    TCHAR szTempFile  [MAX_PATH];    UINT nResult=GetTempFileName (szTempPath, _T ("~ex"),0,szTempfile);    ASSERT (nResult);    strTempName=szTempFile; } 67、如何访问桌面窗口   静态函数CWnd:: GetDesktopWindow 返回桌面窗口的指针。下例说明了MFC 函数CFrameWnd::BeginModalStae是如何使用该函数进入内部窗口列表的。 void CFrameWnd::BeginModalState () {    …    //first count all windows that need to be disabled    UINT nCount=0;    HWND hWnd=:: GetWindow (:: GetDesktopWindow (), GW_CHILD);    while (hWnd!=NULL)    {       if (:: IsWindowEnabled (hwnd) &&           CWnd::FromHandlePermanent (hWnd)!=NULL &&           AfxIsDescendant (pParent->m_hWnd, hWnd) &&           :: SendMessage (hWnd, WM_DISABLEMODAL, 0, 0)==0)       {           ++nCount;       }       hWnd=:: GetWindow (hWnd, GW_HWNDNEXT);    }        … }