bokee.net

电子/电气工程师博客

正文 更多文章

MFC应用框架

                MFC应用框架

               王佰营 徐丽红   整理

          wbymcs51.blog.bokee.net 

  第一部分 Visual C++应用框架揭密
Visual C++应用框架提供的强大功能,为我们的程序开发提供了极大的方便,利用其应用生成器可以很轻松地生成应用程序的框架.许多常用功能,例如文档的创建,文件的打开,保存等操作的大部分代码都由应用框架来完成.这些操作对于开发软件的用户而言,是透明的. Microsoft公司的设计Visual C++的初衷是尽量向用户提供尽可能简单的接口,但是,正是因为应用框架的这一透明性,使Visual C++的运行流程显得非常神秘,当涉及这些Visual C++已经提供的功能模块的软件开发时,用户(特别是那些刚刚接触Visual C++的)不知道什么时候该使用什么接口函数,想改变Visual C++的一些默认操作时也不知道该从哪儿下手,使开发的难度增加.
 本人在编程实践中发现,可以通过Visual C++自带的强大的Debug调试工具,跟踪应用框架代码,从而得出应用框架操作的部分流程.具体实现是:利用Visual C++应用生成器生成应用框架代码,启动 Classwizard,在各个类中加入欲跟踪的接口函数,编辑接口函数,设置断点,再启动Debug进行单步跟踪调试.利用这一方法,我们还可以跟踪 Visual C++提供的例子代码.在跟踪过程中,Visual C++的核心代码是禁止跟踪调试的,我们只要跳过就行.
 以下是本人对多文档应用程序的文档创建,文件的打开, 保存(另存为)操作的跟踪结果,单文档应用与多文档应用的操作流程基本相似,只是用CSingleDocTemplate类的同名函数来替代对 CMultiDocTemplate类同名函数的调用.以下说明中,"应用程序"均指用户生成的基于应用框架的实际程序,"用户代码"指用户在接口函数中加入的代码.
一.创建文档
ON_COMMAND(ID_FILE_NEW,CWinApp::OnFileNew)
入口:CWinApp::OnFileNew
调用:CdocManager::OnFileNew()
1.判断有无文档模板,无则函数返回;
2.判断是否有多个文档模板,如有则启动文档模板选择对话框, 让用户选择一个模板后,返回模板指针.
3.由模板指针访问CMultiDocTemplate::OpenDocumentFile()
 31.创建新文档对象
 32.创建与新文档对象对应的子框架,构筑子框架,文档和视窗之间的关系
 33.调用应用程序的OnNewDocument()
  a.调用CDocument::OnNewDocument()
  调用应用程序的DeleteContents();
  b.用户代码
 34.调用InitialUpdateFrame()显示视窗
 35.返回文档指针
4.返回
二.打开文档
ON_COMMAND(ID_FILE_OPEN,CWinApp::OnFileOpen)
入口:CWinApp::OnFileOpen
调用:CDocManager::OnFileOpen()
1.弹出对话框让用户选择待打开的文件,返回该文件的全路径名称, 供下面函数调用时使用.
2.调用应用程序的OpenDocumentFile(LPCTSTR lpszFileName)
 21.用户代码
 22.调用CWinApp::OpenDocumentFile(lpszFileName),
 调用CWinApp::OpenDocumentFile(lpszFileName),
 调用CDocManager::OpenDocumentFile
  a.判断有无该文件的打开文档对象,有则激活该窗口并返回
  b.调用CMultiDocTemplate::OpenDocumentFile()
   b1.创建新的文档对象,创建新文档对象对应的子框架
   b2.调用应用程序的OnOpenDocument()
   (1)调用CDocument::OnOpenDocument()
    .打开文件对象
    .调用应用程序的DeleteDontents();
    .建立与此文件对象相关联的CArchive对象
    .调用应用程序文档对象的Serialize()函数
    .关闭CArchive对象,文件对象
   (2)显示该文件窗口
   b3.返回
三.文件保存
ON_COMMAND(ID_FILE_SAVE,CDocument::OnFileSave)
入口:CDocument::OnFileSave()
调用:CDocument::DoFileSave()
如果当前文档对应的文件名为空或者为只读文件,以NULL 为参数调用CDocument::DoSave(NULL),否则,以当前文档对应的文件名为参数调用CDocument::DoSave(m_strPathName);

ON_COMMAND(ID_FILE_SAVEAS,CDocument::OnFileSaveAs)
入口:CDocument::OnFileSaveAs()
以NULL为参数直接调用CDocument::DoSave(NULL);
CDocument::DoSave(LPCTSTR lpszPathName,BOOL bReplace);
如果lpszPathName为NULL,
1.设定应用程序默认的文件名
2.打开通用文件保存对话框,由用户设定保存文件的名字,并返回该文件名
 如果lpszPahtName不为NULL,则跳为以上两步,直接进入下一步
3.调用应用程序的OnSaveDocument()
 31.用户代码
 32.调用CDocument::OnSaveDocument()
  a.创建或打开文件对象
  b.建立相对应的CArchive对象
  c.调用应用程序文档对象的序列化函数Serialize()
  d.关闭文件对象,CArchive对象
  e.设置文件未修改标志
4.返回

 

 

   第二部分 VC++的应用程序框架中各类之间的访问方法

Visual C++ 6.0开发环境中,我们可以用MFC AppWizard 自动生成一个应用程序。其中包括了应用类,主边框窗口类,子边框窗口类(MDI 应用程序),文档类和视 图类。另外,系统还自动生成了一个文档模板类对象,它把文档类,文档边框窗口类(SDI 中的主边框窗口类或MDI 中的子边框窗口类),视图类联系在一起,组成一个有机的整体。
    在一些专业教材书中,虽然提到了它们之间的关系,但都没有全面系统地予以介 绍。使得初学 VC 的朋友在各类对象之间相互访问时感到非常困难。笔者经过一段时间 的总结,现将各类对象之间的关系以及相互之间访问的方法介绍如下:
 1。应用类对象 :
   应用类对象由应用框架自动生成。虽然在应用类的 cpp 文件中有一个应用类对象的声明语句,但该对象却无法使用。用户可以通过 CWinApp *AfxGetApp() 全局函数得到指向应用类对象的指针,由于该函数返回值为 CWinApp * 类型,因此需要进行转换。
  用法如下:
      假设您的应用类名为:CExampleApp。
      CExamlpleApp * p=(CExamlpleApp *)AfxGetApp();
      p 即为指向应用类对象的指针。
2。主边框窗口类(CMainFrame):
     主边框窗口类对象的生成较为复杂,对于 MDI 应用程序,主边框窗口类对象由应用类对象在它的 InitInstance()函数中构造生成;对于 SDI 应用程序,主边框窗口类对象由文档模板类构造生成。
    用户可以用下列方式获得指向主边框窗口类对象的指针:
   (1).利用全局函数 AfxGetMainWnd().
   (2).通过应用类的 GetMainWnd() 成员函数或 m_pMainWnd 成员变量。
   (3).对于 MDI 应用程序,还可以通过子边框窗口类的 GetMIDFrame()成员函数
  得到。
    同理,以上各函数的返回值也是 CFrameWnd * 类型( SDI 应用程序)或CMDIFrameWnd * 类型( MDI 应用程序),仍需要转换成 CMainFrame * 类型。
 注:以下各函数的返回值均需要转换成相应类的指针类型。下面不再敖述。
3. 文档模板类:
    文档模板类对象由应用对象在 InitInstance()函数中构造生成。它分为:单文档模板类(CSingleDocTemplate)和多文档模板类(CMultiDocTemplate),分别对应 SDI应用程序和 MDI应用程序。二者均由CDocTemplate派生。文档模板类把文档类,文档边框 窗口类(SDI 中的主边框窗口类或MDI 中的子边框窗口类),视图类联系为一个有机的 整体。应用类对象通常只生成一个文档模板类对象 ,不过用户可以自己生成多个文档模板类对象,从而使SDI 也可以打开多个文档,具有了MDI的特征.所有的文档模板类对象组成了一个链表,应用类的m_pDocManger 成员变量指向该链表。
    用户可以通过应用类的成员函数 GetFirstDocTemplatePosition()和GetNextDocTemplate(POSITION & pos)来访问该链表:
        POSITION pos;
        pos=GetFirstDocTemplatePosition();
        CDocTemplate * pDocTemplate;
        pDocTemplate=GetNextDocTemplate(pos);
   pDocTemplate 即是指向第一个文档模板类对象的指针,用户还可以继续调用GetNextTemplate()得到下一个文档模板类对象.
4。子边框窗口类(CChildFrame):
    子边框窗口类是专门针对 MDI 应用程序而言的,它由文档模板类构造生成。对它的访问可用以下方式实现:
    通过主边框窗口类的 CFrameWnd * GetActiveFrame() 得到指向该对象的指针。
5.文档类:
    文档类对象由文档模板类构造生成。单文档模板类只能生成一个文档类对象,并用成员变量 m_pOnlyDoc 指向该对象。多文档模板类可以生成多个文档类对象,另用成员变量 m_docList 指向文档对象组成的链表。在 SDI 应用程序中,当我们生成多个单文档模板类对象时,就可以打开多个文档。
   用户可以通过多文档模板类对象的成员函数 GetFirstDocPosition() 和GetNextDoc(POSITION &pos) 来访问文档对象组成的链表:
      POSITION pos;
      pos=GetFirstDocPosition();
      CDocument *pDoc;
      pDoc=GetNextDoc(pos);
      另外,文档类还可以通过其成员函数 CDocTemplate * GetDocTemplate() 返过来访问文档模板类对象.
    对于当前活动的文档类对象,我们还可以通过以下方式访问:
    (1).通过子边框窗口(MDI 应用程序)或主边框窗口(SDI 应用程序)的成员函数
CDocument * GetActiveDocument() 可以得到指向该文档的指针.
    (2).另外视图类的成员函数 CDocument * GetDocument()以及成员变量
m_pDocument 也可以得到指向该文档的指针.
6.视图类:
   视图类对象是由主边框窗口(SDI 应用程序)或子边框窗口(MDI 应用程序)构造生成的.因此它的访问方式有以下两种:
(1).对于当前活动的视图类对象可以由主边框窗口(SDI 应用程序)或子边框窗口(MDI 应
用程序)的成员函数 CView * GetAcitveView() 来得到该对象的指针.
   (2).另外,还可以通过文档类的成员函数 GetFirstViewPosition() 和CView *
   GetNextView() 来访问所有的视图类对象。
其用法与上面文档模板类函数类似。

    以上各类的成员变量或成员函数基本上使我们在任何位置都可以访问到应用程序的
每一个角落,但对于频繁性地访问某一固定对象或对运行速度要求较高的场合,我们可以
通过保存该对象的窗口句柄(只限于派生于 CWnd 的类),在需要的时候,通过函数
CWnd::FromHandle(HWND hwnd) 来得到该对象的指针.

                      

 

 

第三部分框架四大对象访问方法

(1)框架四大对象之间的关系(层次关系)
   Cobject
    |
   CCmdtaraget
    |-->CWinthread-CWinApp-[CMyApp];
    |
    |-->CWrd--CView--[CMyVieww];
    |     |
    |     |-->CFrameWrd-[CMainFrame];
    |
    |-->CDocument--CMyDoc.
(2)包含关系
    -------------->CMyApp<----------------
    |        _______|  |_____             |
    |        |               |            |
 MainFram  CMyDOC-------->CMyView      stdafx.h
    |                                     |
    |_____________________________________|
(3)指针获取(符头指向那个对象,表示可以直接以函数获取那个对象的地址指针)
     (应用程序对象)          (窗口外恒对象)
      [CMyApp]<---------------->[CMainFrame]
         |         \    /             |    
         |          \  /              |
         |           \/               |
         |           /\               |
         |          /  \              |
         |         /    \             |
      [CMyDoc]<-----------------[CMyView]
      (document对象)            (View对象)
          
  (4)四个程序的类的构造及析构顺序:
      (a)构造:
          App---->Doc----->Frame----->View;
      (b)析构:
          View--->Frame--->Doc;

 (5)四大对象的指针获取:
     (a)在CMyApp类中:
         <1>获得CMainFrme*pMain=(CMainFrame*)CWinThread::m_pMainWnd;
         <2>获CMyview类对象的指针。
            CMyview*pview=(CMyView*)
             ((CMainFrame*)m_pMainWnd)-->CFrameWnd::GetActiveView();
         <3>获CMyDoc类对象的指针:  
            CMyDoc*pDoc=(CMyDoc*)
             ((CMainFrame*)m_pMainWnd)-->
                 CFrameWnd::GetActiveDocument();
     (b)在CMainFrame类中:   
         <1>获CMainFrame类对象的指针:
            CMainFrame*pMain=(CMainFrame*)CWnd::GetActiveWindow();
         <2>获得CMyDoc类对象指针: 
            CMyDoc*pDoc=(CMyDoc)CFrameWnd::GetActiveDocument(); 
         <3>获CMyView类对象的指针; 
            CMyView*pView=()CMyView*CFrameWnd::GetActiveViw();  
     (c)在CMyDoc类中:
         <1>获CMainFrame类对象的指针。
            CMainFrame*pMain=(CMyainFrame*)AfxGetMainWnd();
            CMainFrame*pMain=(CMyainFrame*)AfxGetApp->m_pMainWnd;
         <2>获CMyView类对象的指针。
           *若只有一个View=须通过CMyainFrame.
            CMyView*pView=(CMyView*)
                 ((CMainFrame*)AfxGetApp()->m_pMainWnd)
                 ->CFrameWnd::GetActiVeView();
           *两个以上View,以找寻CMView为例。
            POSITION pos=CDocument::GeFirstViewPosition();  
            while(pos!=NULL)
                {
                  CView*pView=CDocument::GetNextView(pos);
                  if(pView->GetRuntimeClass()==RUNTIME_CLASS(MYyView)) 
                  {
                    ------
                           };
                };
          *CMyApp类对象指针:
           CWinApp*AfxGetApp()是全局函数,在任何地方都可获得CMyApp 类对象的指针:
     <d>在CMyview类中:  
       (1)获得CMainFrame类对象指针:
            CMainFrame*pMain=(CMainFrame*)AfxGetMainWnd();
            CMainFrame*pMain=(CMainFrame*)CWnd::GetParentframe();
       (2)获得CMyDoc类对象指针:
            CMyDoc*pDoc=GetDocument();

(6)获取指针的时机:
     <a> 获CMainFrame类对象指针: 
         在CMainFrame::ActivateFrame(int n CmdShow)中的CFrameWnd::Actiate
(n Cindshow)
         函数执行完毕之后;
     <b> 获View对象指针:
         在CView::ONCreate 函数执行完毕之后;

     <c> 获Doc对象指针:
         在CView::ONCreate 函数执行完毕之后
(7)获工具条指针:
     <1>CToolBar*pToolBar=(CToolBar*)AfxGetMainWnd()->
                 GetDescendantWindow(AF_IDW_TOOLBAR);
     <2>CTOOLBarCtrl&GetToolBarCtrl()const;
(8)获状态条的指针:
     <1>CStatusBar*pStatus=(CStatus*)AfxGetMainWnd()
        ->GetDescendantWindow(AFX_IDW_STAUSBAR);
     <2>CStatusBar*pStatus=&((CMainFrame*)AfxGetMainWnd())
        ->m_WndStatusBar;
(9)鼠标指针:
    AFxGetApp()->LoadCursor(IDC_CURSORI);
(10)从对话框中获得一个控件的指针,
     CComboBox*ComboBox=(CComboxBox*)GetDlgItem(IDC_COMBO1);
     CListBox*ListBox=(CListBox*)GetDlgItem(IDC_LIST1);
     CScrollBar*scrollbar=(CScorlBar*)GetDlgIetem(IDC_SCROLLBAR1);
(11)获取控件指针:
     GetDlgItem(IDC_BUTTON1)->SetWindowTexts_T("开始");
     GetDlgItem(IDC_EDIT1)->SetWindowText("请输入");
 
(12)将窗口显示在最上面;
  HWND hwand=NULL;
  if(::FindWindow(NULL,_T("文件分析")))
   hwand=::FindWindow(NULL,_T("文件分析"));
  //else
  // if(::FindWindow(NULL,_T("删除文件")))
  // hwand=::FindWindow(NULL,_T("删除文件"));
  if(::IsWindow(hwand))
  {
   ::ShowWindow(hwand,SW_SHOWNORMAL);
   ::BringWindowToTop(hwand);
  }
(13)状态栏指针;
 class CWinThread : public CCmdTarget
 {
  DECLARE_DYNAMIC(CWinThread)

 public:
 // Constructors
  CWinThread();
  BOOL CreateThread(DWORD dwCreateFlags = 0, UINT nStackSize = 0,
  LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);

 // Attributes
  //*********************
  CWnd* m_pMainWnd;  // main window (usually same AfxGetApp()->m_pMainWnd)
  //*********************
  CWnd* m_pActiveWnd;// active main window (may not be m_pMainWnd)
  BOOL m_bAutoDelete;// enables ’delete this’ after thread termination

 // only valid while running
 HANDLE m_hThread;       // this thread’s HANDLE
 operator HANDLE() const;
 DWORD m_nThreadID;      // this thread’s ID
 .......................
 }

 class CMainFrame : public CFrameWnd
 {
 
 protected: // create from serialization only
  CMainFrame();
  DECLARE_DYNCREATE(CMainFrame)

 // Attributes
 public:
  CStatusBar  m_wndStatusBar;
  CToolBar    m_wndToolBar;
 .........................
 }

  CMainFrame* pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;
  CStatusBar* pStatus=&pFrame->m_wndStatusBar;
  if (m_TgtNumHooked!=-1)
  {
 TGTSTRUCT *pTgt;
 pTgt=(m_TxOnly)? &TxTgt[m_TgtNumHooked] : &RxTgt[m_TgtNumHooked];
 sprintf(&buf[0],"x=%6dm, y=%6dm, z=%5dm, vx=%4dm/s, vy=%4dm/s",
    pTgt->x, pTgt->y, pTgt->z, pTgt->vx, pTgt->vy);
 }
 else buf[0]=0;
  pStatus->SetPaneText(pStatus->CommandToIndex(ID_INDICATOR_POS), &buf[0]);

第四部分控制应用程序启动及其他

1. 如何获取应用程序的 实例句柄?
    应用程序的 实例句柄保存在CWinAppIm_hInstance 中,可以这么调用
    AfxGetInstancdHandle获得句柄.
      Example: HANDLE hInstance=AfxGetInstanceHandle();
 
2. 如何通过代码获得应用程序主窗口的 指针?
     主窗口的 指针保存在CWinThread::m_pMainWnd中,调用 AfxGetMainWnd实现。
      AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //使程序最大化.
 
3.如何在程序中获得其他程序的 图标?
      两种方法:
(1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle,
       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);
                   }
              }
        (2) SDK函数 SHGetFileInfo获得有关文件的 很多信息,如大小图标,属性,
           类型等.
           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, shellexecute,createprocess可以使用。
     WinExec最简单,两个参数,前一个指定路径,后一个指定显示方式.后一个参数  值得说一下,比如泥用 SW_SHOWMAXMIZED方式去加栽一个无最大化按钮的 程序,呵呵   就是Neterm,calc等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。
ShellExecute较 WinExex灵活一点,可以指定工作目录,下面的 Example就是直接 打开 c:\temp\1.txt,而不用加栽与 txt文件关联的应用程序,很多安装程序完成后   都会打开一个窗口,来显示Readme or Faq,偶猜就是这么作的啦.
    ShellExecute(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处进行声明,也就是常说的"宏映射"
如何得到系统的当前活动程序的窗口中里具有当前焦点的子窗口的句柄及内容
// 获得Foreground窗口当前焦点窗口的内容
//自己的程序在后台运行
CString CMyWnd::GetForegroudWndFocusWndText(void)
{
CWnd * mainwnd, *subwnd;
DWORD dwthreadforeground, dwthreadthis;

//获得当前活动窗口
mainwnd = GetForegroundWindow();

//获得活动窗口的线程号
dwthreadforeground = ::GetWindowThreadProcessId(mainwnd->m_hWnd, NULL);
//获得与自己程序的窗口相关的线程号
dwthreadthis = ::GetWindowThreadProcessId(m_hWnd, NULL);

//将两个线程的输入联系起来,只有这样,GetFocus函数才能获得其它线程中的焦点窗

::AttachThreadInput(dwthreadthis, dwthreadforeground, TRUE);

//得到当前的具有输入焦点的子窗口
subwnd = GetFocus();

char lpszText[MAX_PATH];
//获得窗口中的文字信息
::SendMessage(subwnd->m_hWnd, WM_GETTEXT, WPARAM(MAX_PATH),LPARAM(lpszText));
//将联到一起的两个线程的输入分离
::AttachThreadInput(dwthreadthis, dwthreadforeground, FALSE);

return lpszText;
}
同理可得到一切窗口的具有当前焦点的子窗口的句柄

改变某个控件及文字的颜色
HBRUSH CMCS51Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
 HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
 if(pWnd->GetDlgCtrlID()==IDCANCEL)
 {
   pDC->SetTextColor(RGB(205,0,195));
   pDC->SetBkColor(RGB(255,255,255));
 }
................
}

//自画按钮;
void MyDialog::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct,CDC* pDC)
{
    CDC dc;
 dc.Attach(lpDrawItemStruct->hDC);
 if(nIDCtl=IDC_SAMPLE)
 {
        CWnd *SampleWnd=GetDlgItem(IDC_SAMPLE);
     CRect SampleRect;
  SampleWnd->GetClientRect(&SampleRect);
  dc.FillSolidRect(&SampleRect,m_colors);
 }
m_colors=RGB(255,0,0);
CWnd *SampleWnd=GetDlgItem(IDC_SAMPLE);
SampleWnd->Invalidate();
SampleWnd->UpdateWindow();
 CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

 关键词:VC MFC 框架 对象 访问

 

 

分享到:

上一篇:Dsp指令的分类

下一篇:

评论 (0条) 发表评论

抢沙发,第一个发表评论
验证码