• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            如需改變標(biāo)題(Caption)時,使之換行可以用c++轉(zhuǎn)義符\n
            vc++中不能改變單個控件的字體,可以使用位圖改變

             

            應(yīng)用程序的一般組成:應(yīng)用程序?qū)ο蠛痛翱趯ο蟆F渲袥]個MFC程序必須有一個應(yīng)用程序?qū)ο螅?fù)責(zé)啟動和終止應(yīng)用程序。
            文檔類:用于管理應(yīng)用程序的數(shù)據(jù)

            視圖類:用于顯示應(yīng)用程序的數(shù)據(jù)

            組件:專用的,自包含的窗口對象,它們通常是構(gòu)成用戶界面的元素。也稱為控件。
            組件必須包含在其他的窗口中,把該窗口成為斧窗口。所以控件也叫做子窗口控件。
            MFC的六種嵌入窗口家族:
            CStatic--用于顯示文本或圖標(biāo)控件
            CButton--按鈕、復(fù)選框、單選按鈕、組框
            CListBox--顯示項(xiàng)目滾動列表的控件
            CComboBox--顯示可縮回的項(xiàng)目列表的控件
            CScrollBar--水平或垂直滾動條
            CEdit--單行或多行文本編輯控件

            資源:特殊形式的只讀數(shù)據(jù),由一個叫做資源編譯器的程序?qū)⒅?lián)編到可執(zhí)行程序中。
            資源的兩種基本形式:
            二進(jìn)制--圖形資源,包括圖標(biāo)、光標(biāo)和位圖
            文本--結(jié)構(gòu)化的資源,包括對話框、菜單、字符串表和加速鍵表。
            二進(jìn)制資源存儲在一個獨(dú)立的文件中,文本資源存儲在普通的ASCII文本文件中,該文件描述了每個元素的結(jié)構(gòu)。該ASSCII文件稱為資源描述文件--通常與你的項(xiàng)目同名,其擴(kuò)展名為.rc


            DECLARE_MESSAGE_MAP()該宏告訴VisualC++這個類將響應(yīng)Windows消息,該入口以及在實(shí)現(xiàn)文件中的相應(yīng)映射入口,是用于建立消息映射的高級宏系統(tǒng)的部分。消息映射保證Windows消息被交給正確的成員函數(shù)。

            #include "stdafx.h"是所有MFC程序都要用到的標(biāo)準(zhǔn)應(yīng)用程序框架頭文件。它引入用語標(biāo)準(zhǔn)MFC組件、大多數(shù)通用擴(kuò)展以及Internet Explorer4常用控件的定義。

            正式版和調(diào)試版的轉(zhuǎn)換:使用Build|Set Active Configuration.

            構(gòu)造函數(shù)和InitInstance()函數(shù):
            構(gòu)造函數(shù)是在對象創(chuàng)建是調(diào)用的。InitInstance()是在WinMain()調(diào)用時重載的。所以夠找函數(shù)是在WinMain()被調(diào)用前調(diào)用的。此時,很多MFC系統(tǒng)還沒有完成自身的初始化,只有在主應(yīng)用程序?qū)ο蟊粯?gòu)造完畢,WinMain()才會被調(diào)用。

            在一個API應(yīng)用程序中,WinMain()函數(shù)有三個任務(wù),它必須完成:
            1、注冊一個新的主窗口類
            2、創(chuàng)建一個窗口的實(shí)例并顯示它
            3、運(yùn)行消息循環(huán)
            InitInstance()函數(shù)為MFC的WinMain()函數(shù)執(zhí)行以上內(nèi)容的第二項(xiàng)內(nèi)容。

            關(guān)于CWinApp
            MFC中CWinApp類定義的關(guān)鍵幾個虛函數(shù)或可重載函數(shù)
            1、InitInstance()肯定是要被重載的
            2、Run()掃描消息并處理消息。
            3、OnIdlc(),當(dāng)Run()在沒有消息要處理事就要調(diào)用該函數(shù)。OnIdle()可利用該機(jī)會執(zhí)行后臺任務(wù),否則該后臺任務(wù)會降低系統(tǒng)反應(yīng)速度。
            4、ExitInstance(),當(dāng)一個應(yīng)用程序結(jié)束時由Run()進(jìn)行調(diào)用。

            基于CDialog的窗口是以局部變量的形式在棧中創(chuàng)建的,而基于CWnd的窗口是以動態(tài)變量的形式在自由存儲器(freestore)中創(chuàng)建的 。
            故有對于基于CDialog類:
            CFourUpdlg dlg;
            m_pMainWnd=&dlg;
            對于基于CWnd的類:
            m_pMainWnd=new CMainWindow;

            CFourUpDlg::CFourUpDlg(CWnd* pParent /*=NULL*/)
             : CDialog(CFourUpDlg::IDD, pParent)
            構(gòu)造函數(shù)中CFourUpDlg::IDD的 IDD是個枚舉量(定義在頭文件中),包含對話框模板的資源ID(包含在資源描述中)。表示CDialog構(gòu)造函數(shù)從對話框模板中讀出信息,然后構(gòu)造一個窗口,在構(gòu)造過程使用的是由模板給出的規(guī)范。為了創(chuàng)建對話框窗口(并且所有的控件都包含在對話框模板中),CDialog構(gòu)造函數(shù)使用CWnd::Create()或CWnd::CreateEx()函數(shù),對主對話框調(diào)用該函數(shù)一次并對它碰到的每個控件都調(diào)用一次。

            CWnd:Create()函數(shù)
            原型:
            virtual BOOL Create(LPCTSTR lpszClassName,LPCTSTR lpszWindowName,DWORD dwStyle,const RECT & rect,UINT nID,CCreateContext * pContext=NULL);


            在Windows中,每個窗口都分成兩大部分:非客戶區(qū)(包括標(biāo)題條,窗口邊界)和客戶區(qū)。
            其中Windows負(fù)責(zé)非客戶區(qū)的繪制

            每當(dāng)Windows想繪制一個窗口的客戶區(qū)時,Windows便向該窗口發(fā)送WM_PAINT消息,通常由OnPaint()成員函數(shù)。
            OnPaint()大致分為:
            1.獲取畫布或繪制平面,在Windows中,使用的繪制平面稱為設(shè)備環(huán)境(device context,DC).
            2.建立環(huán)境,包括收集所有需要的畫筆和畫刷,并測量工作平面的大小,以便能夠正確地在改平面上對其圖案.
            3.用Windows圖形庫GDI中地函數(shù)繪制窗口

            只可以在OnPaint()中創(chuàng)建CPaintDC對象.
            需要在其他地方繪制時用CClientDC
            調(diào)用CWnd::Invalidate()可以重畫整個窗口.

            畫筆:用來畫線或圖形邊框的顏色
            刷子:用于填充圖形或繪制窗口背景的顏色
            庫存對象(stock object):Windows提供的幾種嵌入式的畫筆和刷子.可以通過SelectStockObject()選擇.

            定時器創(chuàng)建:SetTimer(),它有三個函數(shù):
            1.定時器ID--區(qū)別不同的定時器實(shí)例.
            2.定時器間隔--最大分辨率55毫秒
            3.定時器回調(diào)函數(shù)--特殊的回調(diào)函數(shù)的地址,該函數(shù)用于處理定時器消息.如果值為NULL,Windows將向你通知WM_TIMER消息.
            在基于對話框的應(yīng)用程序中,OnInitDialog()函數(shù)是最佳的創(chuàng)建定時器的地方.如果創(chuàng)建成功,SetTimer()函數(shù)返回的定時器ID于所使用的函數(shù)相同.
            刪除定時器:
            KillTimer()向之傳遞構(gòu)造定時器所使用的ID.定時器是個受限的全局資源.當(dāng)用完定時器后,調(diào)KillTimer()是個必須的過程.通常可以相應(yīng)WM_DESTORY消息時處理KillTimer()函數(shù)
            定時器的相應(yīng):
            當(dāng)計(jì)數(shù)器溢出時,產(chǎn)生一個WM_TIMER消息,通常在OnTimer()處理WM_TIMER消息


            創(chuàng)建畫筆:
            第一種:使用構(gòu)造函數(shù),如:CPen greePen(PS_SOLID,10,RGB(0,255,0));
            第二種:兩步法
            CPen greenPen;
            greePen.CreatePen(PS_SOLID,10,RGB(0,255,0));
            第三中:創(chuàng)建LOGPEN結(jié)構(gòu)的實(shí)例來構(gòu)造
            LOGPEN lp;
            lp.lopnstyle=PS_SDLID;
            lp.lopnWidth=10;
            lp.lopnColor=RGB(0,255,0);
            Cpen greenPen;
            GreenPen.CreatePenIndirect(&lp);

            posted @ 2008-12-15 21:20 wrh 閱讀(259) | 評論 (0)編輯 收藏

            函數(shù):fopen()


            fopen

            打開文件或者 URL。

            語法: int fopen(string filename, string mode);

            返回值: 整數(shù)

            函數(shù)種類: 文件存取

            內(nèi)容說明

            說明: 本函數(shù)可用來打開本地或者遠(yuǎn)端的文件。若參數(shù) filename 為 "http://......" 則本函數(shù)利用 HTTP 1.0 協(xié)議與服務(wù)器連接,文件指針則指到服務(wù)器返回文件的起始處。若參數(shù) filename 為 "ftp://......." 則本函數(shù)會與服務(wù)器連接,文件指針指到指定的文件處。若 FTP 服務(wù)器沒有支持被動模式 (passive mode ftp) 則返回失敗值。打開的 FTP 文件可以是讀取或?qū)懭肫渲兄唬荒茏x或?qū)懚N同時使用。其它的情形,本函數(shù)打開本地的文件,文件的指針則指向打開的文件。若開文件失敗,則返回 false 值。

            字符串參數(shù) mode 可以是下列的情形:

            • 'r' 開文件方式為只讀,文件指針指到開始處。
            • 'r+' 開文件方式為可讀寫,文件指針指到開始處。
            • 'w' 開文件方式為寫入,文件指針指到開始處,并將原文件的長度設(shè)為 0。若文件不存在,則建立新文件。
            • 'w+' 開文件方式為可讀寫,文件指針指到開始處,并將原文件的長度設(shè)為 0。若文件不存在,則建立新文件。
            • 'a' 開文件方式為寫入,文件指針指到文件最后。若文件不存在,則建立新文件。
            • 'a+' 開文件方式為可讀寫,文件指針指到文件最后。若文件不存在,則建立新文件。
            • 'b' 若操作系統(tǒng)的文字及二進(jìn)位文件不同,則可以用此參數(shù),UNIX 系統(tǒng)不需要使用本參數(shù)。

            使用范例

            第一行為 UNIX 系統(tǒng)使用;第二行是 Windows 系列系統(tǒng)的用法;第三、四行則為 URL 的使用范例。

            <?       
            $fp 
            fopen("/home/rasmus/file.txt""r");
            $fp fopen("c:\\mydata\\info.txt""r");
            $fp fopen("http://www.php.net/""r");
            $fp fopen("ftp://user:password@my.com/""w");
            ?>

            參考

            fclose()  popen()  fsockopen()

            posted @ 2008-12-13 19:21 wrh 閱讀(503) | 評論 (0)編輯 收藏
            ---- 方法一:調(diào)用CWinApp類的成員函數(shù)SetDialogBkColor來實(shí)現(xiàn)。
            ---- 其中函數(shù)的第一個參數(shù)指定了背景顏色,第二個參數(shù)指定了文本顏色。下面的例子是將應(yīng)用程序?qū)υ捒蛟O(shè)置為藍(lán)色背景和紅色文本,步驟如下:
            ---- ① 新建一個基于Dialog的MFC AppWizard應(yīng)用程序ExampleDlg。
            ---- ② 在CExampleDlgApp ::InitInstance()中添加如下代碼:
            BOOL CExampleDlgApp: : InitInstance ( )
            {
            ...
                CExampleDlgDlg dlg;
                m_pMainWnd = &dlg;
            //先于DoModal()調(diào)用,將對話框設(shè)置為藍(lán)色背景、紅色文本
                SetDialogBkColor(RGB(0,0,255),RGB(255,0,0));
                int nResponse = dlg.DoModal();
            ...
            }
            ---- 編譯并運(yùn)行,此時對話框的背景色和文本色已發(fā)生了改變。值得注意的是:在調(diào)用DoModal()之前必須先調(diào)用SetDialogBkColor,且此方法是將改變應(yīng)用程序中所有的對話框顏色,并不能針對某一個指定的對話框。
            ---- 方法二:重載OnPaint(),即WM_PAINT消息。有關(guān)代碼如下(以上例工程為準(zhǔn)):
            void CExampleDlgDlg::OnPaint()
            {
                if (IsIconic())
            ...
              else
              {
                    CRect rect;
                    CPaintDC dc(this);
                    GetClientRect(rect);
                    dc.FillSolidRect(rect,RGB(0,255,0));  //設(shè)置為綠色背景
                    CDialog::OnPaint();
              }
            ---- 方法三:重載OnCtlColor (CDC* pDC, CWnd* pWnd, UINT nCtlColor),即WM_CTLCOLOR消息。具體步驟如下(以上例工程為準(zhǔn)):
            ---- ①在CExampleDlgDlg的頭文件中,添加一CBrush的成員變量:
            class CExampleDlgDlg : public CDialog
            {
            ...
            protected:
            CBrush m_brush;
            ...
            };
            ---- ②在OnInitDialog()函數(shù)中添加如下代碼:
            BOOL CExampleDlgDlg::OnInitDialog()
            {
            ...
            // TODO: Add extra initialization here
            m_brush.CreateSolidBrush(RGB(0, 255, 0)); // 生成一綠色刷子
            ...
            }
            ---- ③利用ClassWizard重載OnCtlColor(...),即WM_CTLCOLOR消息:
            HBRUSH CExampleDlgDlg::OnCtlColor
            (CDC* pDC, CWnd* pWnd, UINT nCtlColor)
            {
            /*
            ** 這里不必編寫任何代碼!
            **下行代碼要注釋掉
            ** HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
            */
            return m_brush;  //返加綠色刷子
            }
            ---- 方法四:還是重載OnCtlColor (CDC* pDC, CWnd* pWnd, UINT nCtlColor),即WM_CTLCOLOR消息。具體步驟如下(以上例工程為準(zhǔn)):
            ---- 步驟①、②同上方法三中的步驟①、②。
            ---- 步驟③利用ClassWizard重載OnCtlColor(...)(即WM_CTLCOLOR消息)時則有些不同:
            HBRUSH CExampleDlgDlg::OnCtlColor
            (CDC* pDC, CWnd* pWnd, UINT nCtlColor)
            {
            HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
            //在這加一條是否為對話框的判斷語句
            if(nCtlColor ==CTLCOLOR_DLG)
            return m_brush;  //返加綠色刷子
            return hbr;
            }
            ---- 編譯并運(yùn)行即可。
            posted @ 2008-11-05 16:01 wrh 閱讀(1686) | 評論 (0)編輯 收藏

            1. MFC和Win32

               

              1. MFC Object和Windows Object的關(guān)系

                 

            MFC中最重要的封裝是對Win32 API的封裝,因此,理解Windows Object和MFC Object (C++對象,一個C++類的實(shí)例)之間的關(guān)系是理解MFC的關(guān)鍵之一。所謂Windows Object(Windows對象)是Win32下用句柄表示的Windows操作系統(tǒng)對象;所謂MFC Object (MFC對象)是C++對象,是一個C++類的實(shí)例,這里(本書范圍內(nèi))MFC Object是有特定含義的,指封裝Windows Object的C++ Object,并非指任意的C++ Object。

            MFC Object 和Windows Object是不一樣的,但兩者緊密聯(lián)系。以窗口對象為例:

            一個MFC窗口對象是一個C++ CWnd類(或派生類)的實(shí)例,是程序直接創(chuàng)建的。在程序執(zhí)行中它隨著窗口類構(gòu)造函數(shù)的調(diào)用而生成,隨著析構(gòu)函數(shù)的調(diào)用而消失。而Windows窗口則是Windows系統(tǒng)的一個內(nèi)部數(shù)據(jù)結(jié)構(gòu)的實(shí)例,由一個“窗口句柄”標(biāo)識,Windows系統(tǒng)創(chuàng)建它并給它分配系統(tǒng)資源。Windows窗口在MFC窗口對象創(chuàng)建之后,由CWnd類的Create成員函數(shù)創(chuàng)建,“窗口句柄”保存在窗口對象的m_hWnd成員變量中。Windows窗口可以被一個程序銷毀,也可以被用戶的動作銷毀。MFC窗口對象和Windows窗口對象的關(guān)系如圖2-1所示。其他的Windows Object和對應(yīng)的MFC Object也有類似的關(guān)系。

            下面,對MFC Object和Windows Object作一個比較。有些論斷對設(shè)備描述表(MFC類是CDC,句柄是HDC)可能不適用,但具體涉及到時會指出。

            1. 從數(shù)據(jù)結(jié)構(gòu)上比較

               

              MFC Object是相應(yīng)C++類的實(shí)例,這些類是MFC或者程序員定義的;

              Windows Object是Windows系統(tǒng)的內(nèi)部結(jié)構(gòu),通過一個句柄來引用;

              MFC給這些類定義了一個成員變量來保存MFC Object對應(yīng)的Windows Object的句柄。對于設(shè)備描述表CDC類,將保存兩個HDC句柄。

            2. 從層次上講比較

               

              MFC Object是高層的,Windows Object是低層的;

              MFC Object封裝了Windows Object的大部分或全部功能,MFC Object的使用者不需要直接應(yīng)用Windows Object的HANDLE(句柄)使用Win32 API,代替它的是引用相應(yīng)的MFC Object的成員函數(shù)。

            3. 從創(chuàng)建上比較

               

              MFC Object通過構(gòu)造函數(shù)由程序直接創(chuàng)建;Windows Object由相應(yīng)的SDK函數(shù)創(chuàng)建。

              MFC中,使用這些MFC Object,一般分兩步:

              首先,創(chuàng)建一個MFC Object,或者在STACK中創(chuàng)建,或者在HEAP中創(chuàng)建,這時,MFC Object的句柄實(shí)例變量為空,或者說不是一個有效的句柄。

              然后,調(diào)用MFC Object的成員函數(shù)創(chuàng)建相應(yīng)的Windows Object,MFC的句柄變量存儲一個有效句柄。

              CDC(設(shè)備描述表類)的創(chuàng)建有所不同,在后面的2.3節(jié)會具體說明CDC及其派生類的創(chuàng)建和使用。

              當(dāng)然,可以在MFC Object的構(gòu)造函數(shù)中創(chuàng)建相應(yīng)的Windows對象,MFC的GDI類就是如此實(shí)現(xiàn)的,但從實(shí)質(zhì)上講,MFC Object的創(chuàng)建和Windows Object的創(chuàng)建是兩回事。

            4. 從轉(zhuǎn)換上比較

               

              可以從一個MFC Object得到對應(yīng)的Windows Object的句柄;一般使用MFC Object的成員函數(shù)GetSafeHandle得到對應(yīng)的句柄。

              可以從一個已存在的Windows Object創(chuàng)建一個對應(yīng)的MFC Object; 一般使用MFC Object的成員函數(shù)Attach或者FromHandle來創(chuàng)建,前者得到一個永久性對象,后者得到的可能是一個臨時對象。

            5. 從使用范圍上比較

               

              MFC Object對系統(tǒng)的其他進(jìn)程來說是不可見、不可用的;而Windows Object一旦創(chuàng)建,其句柄是整個Windows系統(tǒng)全局的。一些句柄可以被其他進(jìn)程使用。典型地,一個進(jìn)程可以獲得另一進(jìn)程的窗口句柄,并給該窗口發(fā)送消息。

              對同一個進(jìn)程的線程來說,只可以使用本線程創(chuàng)建的MFC Object,不能使用其他線程的MFC Object。

            6. 從銷毀上比較

               

            MFC Object隨著析構(gòu)函數(shù)的調(diào)用而消失;但Windows Object必須由相應(yīng)的Windows系統(tǒng)函數(shù)銷毀。

            設(shè)備描述表CDC類的對象有所不同,它對應(yīng)的HDC句柄對象可能不是被銷毀,而是被釋放。

            當(dāng)然,可以在MFC Object的析構(gòu)函數(shù)中完成Windows Object的銷毀,MFC Object的GDI類等就是如此實(shí)現(xiàn)的,但是,應(yīng)該看到:兩者的銷毀是不同的。

            每類Windows Object都有對應(yīng)的MFC Object,下面用表格的形式列出它們之間的對應(yīng)關(guān)系,如表2-1所示:

            表2-1 MFC Object和Windows Object的對應(yīng)關(guān)系

            描述

            Windows句柄

            MFC Object

            窗口

            HWND

            CWnd and CWnd-derived classes

            設(shè)備上下文

            HDC

            CDC and CDC-derived classes

            菜單

            HMENU

            CMenu

            HPEN

            CGdiObject類,CPen和CPen-derived classes

            刷子

            HBRUSH

            CGdiObject類,CBrush和CBrush-derived classes

            字體

            HFONT

            CGdiObject類,CFont和CFont-derived classes

            位圖

            HBITMAP

            CGdiObject類,CBitmap和CBitmap-derived classes

            調(diào)色板

            HPALETTE

            CGdiObject類,CPalette和CPalette-derived classes

            區(qū)域

            HRGN

            CGdiObject類,CRgn和CRgn-derived classes

            圖像列表

            HimageLIST

            CimageList和CimageList-derived classes

            套接字

            SOCKET

            CSocket,CAsynSocket及其派生類

             

             


            表2-1中的OBJECT分以下幾類:

             

            Windows對象,

            設(shè)備上下文對象,

            GDI對象(BITMAP,BRUSH,F(xiàn)ONT,PALETTE,PEN,RGN),

            菜單,

            圖像列表,

            網(wǎng)絡(luò)套接字接口。

            從廣義上來看,文檔對象和文件可以看作一對MFC Object和Windows Object,分別用CDocument類和文件句柄描述。

            后續(xù)幾節(jié)分別對前四類作一個簡明扼要的論述。

              1. Windows Object

                 

                用SDK的Win32 API編寫各種Windows應(yīng)用程序,有其共同的規(guī)律:首先是編寫WinMain函數(shù),編寫處理消息和事件的窗口過程WndProc,在WinMain里頭注冊窗口(Register Window),創(chuàng)建窗口,然后開始應(yīng)用程序的消息循環(huán)。

                MFC應(yīng)用程序也不例外,因?yàn)镸FC是一個建立在SDK API基礎(chǔ)上的編程框架。對程序員來說所不同的是:一般情況下,MFC框架自動完成了Windows登記、創(chuàng)建等工作。

                下面,簡要介紹MFC Window對Windows Window的封裝。

                1. Windows的注冊

                   

            一個應(yīng)用程序在創(chuàng)建某個類型的窗口前,必須首先注冊該“窗口類”(Windows Class)。注意,這里不是C++類的類。Register Window把窗口過程、窗口類型以及其他類型信息和要登記的窗口類關(guān)聯(lián)起來。

            1. “窗口類”的數(shù)據(jù)結(jié)構(gòu)

               

              “窗口類”是Windows系統(tǒng)的數(shù)據(jù)結(jié)構(gòu),可以把它理解為Windows系統(tǒng)的類型定義,而Windows窗口則是相應(yīng)“窗口類”的實(shí)例。Windows使用一個結(jié)構(gòu)來描述“窗口類”,其定義如下:

              typedef struct _WNDCLASSEX {

              UINT cbSize; //該結(jié)構(gòu)的字節(jié)數(shù)

              UINT style; //窗口類的風(fēng)格

              WNDPROC lpfnWndProc; //窗口過程

              int cbClsExtra;

              int cbWndExtra;

              HANDLE hInstance; //該窗口類的窗口過程所屬的應(yīng)用實(shí)例

              HICON hIcon; //該窗口類所用的像標(biāo)

              HCURSOR hCursor; //該窗口類所用的光標(biāo)

              HBRUSH hbrBackground; //該窗口類所用的背景刷

              LPCTSTR lpszMenuName; //該窗口類所用的菜單資源

              LPCTSTR lpszClassName; //該窗口類的名稱

              HICON hIconSm; //該窗口類所用的小像標(biāo)

              } WNDCLASSEX;

              從“窗口類”的定義可以看出,它包含了一個窗口的重要信息,如窗口風(fēng)格、窗口過程、顯示和繪制窗口所需要的信息,等等。關(guān)于窗口過程,將在后面消息映射等有關(guān)章節(jié)作詳細(xì)論述。

              Windows系統(tǒng)在初始化時,會注冊(Register)一些全局的“窗口類”,例如通用控制窗口類。應(yīng)用程序在創(chuàng)建自己的窗口時,首先必須注冊自己的窗口類。在MFC環(huán)境下,有幾種方法可以用來注冊“窗口類”,下面分別予以討論。

            2. 調(diào)用AfxRegisterClass注冊

               

              AfxRegisterClass函數(shù)是MFC全局函數(shù)。AfxRegisterClass的函數(shù)原型:

              BOOL AFXAPI AfxRegisterClass(WNDCLASS *lpWndClass);

              參數(shù)lpWndClass是指向WNDCLASS結(jié)構(gòu)的指針,表示一個“窗口類”。

              首先,AfxRegisterClass檢查希望注冊的“窗口類”是否已經(jīng)注冊,如果是則表示已注冊,返回TRUE,否則,繼續(xù)處理。

              接著,調(diào)用::RegisterClass(lpWndClass)注冊窗口類;

              然后,如果當(dāng)前模塊是DLL模塊,則把注冊“窗口類”的名字加入到模塊狀態(tài)的域m_szUnregisterList中。該域是一個固定長度的緩沖區(qū),依次存放模塊注冊的“窗口類”的名字(每個名字是以“\n\0”結(jié)尾的字符串)。之所以這樣做,是為了DLL退出時能自動取消(Unregister)它注冊的窗口類。至于模塊狀態(tài)將在后面第9章詳細(xì)的討論。

              最后,返回TRUE表示成功注冊。

            3. 調(diào)用AfxRegisterWndClass注冊

               

              AfxRegisterWndClass函數(shù)也是MFC全局函數(shù)。AfxRegisterWndClass的函數(shù)原型:

              LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle,

              HCURSOR hCursor, HBRUSH hbrBackground, HICON hIcon)

              參數(shù)1指定窗口類風(fēng)格;

              參數(shù)2、3、4分別指定該窗口類使用的光標(biāo)、背景刷、像標(biāo)的句柄,缺省值是0。

              此函數(shù)根據(jù)窗口類屬性動態(tài)地產(chǎn)生窗口類的名字,然后,判斷是否該類已經(jīng)注冊,是則返回窗口類名;否則用指定窗口類的屬性(窗口過程指定為缺省窗口過程),調(diào)用AfxRegisterCalss注冊窗口類,返回類名。

              動態(tài)產(chǎn)生的窗口類名字由以下幾部分組成(包括冒號分隔符):

              如果參數(shù)2、3、4全部為NULL,則由三部分組成。

              “Afx”+“:”+模塊實(shí)例句柄”+“:”+“窗口類風(fēng)格”

              否則,由六部分組成:

              “Afx”+“:”+模塊實(shí)例句柄+“:”+“窗口類風(fēng)格”+“:”+光標(biāo)句柄+“:”+背景刷句柄+“:”+像標(biāo)句柄。比如:“Afx:400000:b:13de:6:32cf”。

              該函數(shù)在MFC注冊主邊框或者文檔邊框“窗口類”時被調(diào)用。具體怎樣用在5.3.3.3節(jié)會指出。

            4. 隱含的使用MFC預(yù)定義的的窗口類

               

              MFC4.0以前的版本提供了一些預(yù)定義的窗口類,4.0以后不再預(yù)定義這些窗口類。但是,MFC仍然沿用了這些窗口類,例如:

              用于子窗口的“AfxWnd”;

              用于邊框窗口(SDI主窗口或MDI子窗口)或視的“AfxFrameOrView”;

              用于MDI主窗口的“AfxMDIFrame”;

              用于標(biāo)準(zhǔn)控制條的“AfxControlBar”。

              這些類的名字就 是“AfxWnd”、“AfxFrameOrView”、“AfxMdiFrame”、 “AfxControlBar”加上前綴和后綴(用來標(biāo)識版本號或是否調(diào)試版等)。它們使用標(biāo)準(zhǔn)應(yīng)用程序像標(biāo)、標(biāo)準(zhǔn)文檔像標(biāo)、標(biāo)準(zhǔn)光標(biāo)等標(biāo)準(zhǔn)資源。為了使用這些“窗口類”,MFC會在適當(dāng)?shù)臅r候注冊這些類:或者要創(chuàng)建該類的窗口時,或者創(chuàng)建應(yīng)用程序的主窗口時,等等。

              MFC內(nèi)部使用了函數(shù)

              BOOL AFXAPI AfxEndDeferRegisterClass(short fClass)

              來幫助注冊上述原MFC版本的預(yù)定義“窗口類”。參數(shù)fClass區(qū)分了那些預(yù)定義窗口的類型。根據(jù)不同的類型,使用不同的窗口類風(fēng)格、窗口類名字等填充WndClass的域,然后調(diào)用AfxRegisterClass注冊窗口類。并且注冊成功之后,通過模塊狀態(tài)的m_fRegisteredClasses記錄該窗口類已經(jīng)注冊,這樣該模塊在再次需要注冊這些窗口類之前可以查一下m_fRegisteredClasses,如果已經(jīng)注冊就不必浪費(fèi)時間了。為此,MFC內(nèi)部使用宏

              AfxDeferRegisterClass(short fClass)

              來注冊“窗口類”,如果m_fRegisteredClasses記錄了注冊的窗口類,返回TRUE,否則,調(diào)用AfxEndDeferRegisterClass注冊。

              注冊這些窗口類的例子:

              MFC在加載邊框窗口時,會自動地注冊“AfxFrameOrView”窗口類。在創(chuàng)建視時,就會使用該“窗口類”創(chuàng)建視窗口。當(dāng)然,如果創(chuàng)建視窗口時,該“窗口類”還沒有注冊,MFC將先注冊它然后使用它創(chuàng)建視窗口。

              不過,MFC并不使用”AfxMDIFrame”來創(chuàng)建MDI主窗口,因?yàn)樵诩虞d主窗口時一般都指定了主窗口的資源,MFC使用指定的像標(biāo)注冊新的MDI主窗口類(通過函數(shù)AfxRegisterWndClass完成,因此“窗口類”的名字是動態(tài)產(chǎn)生的)。

              MDI子窗口類似于上述MDI主窗口的處理。

              在MFC創(chuàng)建控制窗口時,如工具欄窗口,如果“AfxControlBar”類還沒有注冊,則注冊它。注冊過程很簡單,就是調(diào)用::InitCommonControl加載通用控制動態(tài)連接庫。

            5. 調(diào)用::RegisterWndClass。

               

              直接調(diào)用Win32的窗口注冊函數(shù)::RegisterWndClass注冊“窗口類”,這樣做有一個缺點(diǎn):如果是DLL模塊,這樣注冊的“窗口類”在程序退出時不會自動的被取消注冊(Unregister)。所以必須記得在DLL模塊退出時取消它所注冊的窗口類。

            6. 子類化

               

            子類化(Subclass)一個“窗口類”,可自動地得到它的“窗口類”屬性。

                1. MFC窗口類CWnd

                   

            在Windows系統(tǒng)里,一個窗口的屬性分兩個地方存放:一部分放在“窗口類”里頭,如上所述的在注冊窗口時指定;另一部分放在Windows Object本身,如:窗口的尺寸,窗口的位置(X,Y軸),窗口的Z軸順序,窗口的狀態(tài)(ACTIVE,MINIMIZED,MAXMIZED,RESTORED…),和其他窗口的關(guān)系(父窗口,子窗口…),窗口是否可以接收鍵盤或鼠標(biāo)消息,等等。

            為了表達(dá)所有這些窗口的共性,MFC設(shè)計(jì)了一個窗口基類CWnd。有一點(diǎn)非常重要,那就是CWnd提供了一個標(biāo)準(zhǔn)而通用的MFC窗口過程,MFC下所有的窗口都使用這個窗口過程。至于通用的窗口過程卻能為各個窗口實(shí)現(xiàn)不同的操作,那就是MFC消息映射機(jī)制的奧秘和作用了。這些,將在后面有關(guān)章節(jié)詳細(xì)論述。

            CWnd提供了一系列成員函數(shù),或者是對Win32相關(guān)函數(shù)的封裝,或者是CWnd新設(shè)計(jì)的一些函數(shù)。這些函數(shù)大致如下。

            (1)窗口創(chuàng)建函數(shù)

            這里主要討論函數(shù)Create和CreateEx。它們封裝了Win32窗口創(chuàng)建函數(shù)::CreateWindowEx。Create的原型如下:

            BOOL CWnd::Create(LPCTSTR lpszClassName,

            LPCTSTR lpszWindowName, DWORD dwStyle,

            const RECT& rect,

            CWnd* pParentWnd, UINT nID,

            CCreateContext* pContext)

            Create是一個虛擬函數(shù),用來創(chuàng)建子窗口(不能創(chuàng)建桌面窗口和POP UP窗口)。CWnd的基類可以覆蓋該函數(shù),例如邊框窗口類等覆蓋了該函數(shù)以實(shí)現(xiàn)邊框窗口的創(chuàng)建,視類則使用它來創(chuàng)建視窗口。

            Create調(diào)用了成員函數(shù)CreateEx。CWnd::CreateEx的原型如下:

            BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

            LPCTSTR lpszWindowName, DWORD dwStyle,

            int x, int y, int nWidth, int nHeight,

            HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

            CreateEx有11個參數(shù),它將調(diào)用::CreateWindowEx完成窗口的創(chuàng)建,這11個參數(shù)對應(yīng)地傳遞給::CreateWindowEx。參數(shù)指定了窗口擴(kuò)展風(fēng)格、“窗口類”、窗口名、窗口大小和位置、父窗口句柄、窗口菜單和窗口創(chuàng)建參數(shù)。

            CreateEx的處理流程將在后面4.4.1節(jié)討論窗口過程時分析。

            窗口創(chuàng)建時發(fā)送WM_CREATE消息,消息參數(shù)lParam指向一個CreateStruct結(jié)構(gòu)的變量,該結(jié)構(gòu)有11個域,其描述見后面4.4.1節(jié)對窗口過程的分析,Windows使用和CreateEx參數(shù)一樣的內(nèi)容填充該變量。

            (2)窗口銷毀函數(shù)

            例如:

            DestroyWindow函數(shù) 銷毀窗口

            PostNcDestroy( ),銷毀窗口后調(diào)用,虛擬函數(shù)

            (3)用于設(shè)定、獲取、改變窗口屬性的函數(shù),例如:

            SetWindowText(CString tiltle) 設(shè)置窗口標(biāo)題

            GetWindowText() 得到窗口標(biāo)題

            SetIcon(HICON hIcon, BOOL bBigIcon);設(shè)置窗口像標(biāo)

            GetIcon( BOOL bBigIcon ) ;得到窗口像標(biāo)

            GetDlgItem( int nID);得到窗口類指定ID的控制子窗口

            GetDC(); 得到窗口的設(shè)備上下文

            SetMenu(CMenu *pMenu); 設(shè)置窗口菜單

            GetMenu();得到窗口菜單

            (4)用于完成窗口動作的函數(shù)

            用于更新窗口,滾動窗口,等等。一部分成員函數(shù)設(shè)計(jì)成或可重載(Overloaded)函數(shù),或虛擬(Overridden)函數(shù),或MFC消息處理函數(shù)。這些函數(shù)或者實(shí)現(xiàn)了一部分功能,或者僅僅是一個空函數(shù)。如:

            • 有關(guān)消息發(fā)送的函數(shù):

               

            SendMessage( UINT message,WPARAM wParam = 0, LPARAM lParam = 0 );

            給窗口發(fā)送發(fā)送消息,立即調(diào)用方式

            PostMessage(( UINT message,WPARAM wParam = 0, LPARAM lParam = 0 );

            給窗口發(fā)送消息,放進(jìn)消息隊(duì)列

            • 有關(guān)改變窗口狀態(tài)的函數(shù)

               

            MoveWindow( LPCRECT lpRect, BOOL bRepaint = TRUE );

            移動窗口到指定位置

            ShowWindow(BOOL );顯示窗口,使之可見或不可見

            ….

            • 實(shí)現(xiàn)MFC消息處理機(jī)制的函數(shù):

               

            virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam ); 窗口過程,虛擬函數(shù)

            virtual BOOL OnCommand( WPARAM wParam, LPARAM lParam );處理命令消息

            • 消息處理函數(shù):

               

            OnCreate( LPCREATESTRUCT lpCreateStruct );MFC窗口消息處理函數(shù),窗口創(chuàng)建時由MFC框架調(diào)用

            OnClose();MFC窗口消息處理函數(shù),窗口創(chuàng)建時由MFC框架調(diào)用

            • 其他功能的函數(shù)

               

            CWnd的導(dǎo)出類是類型更具體、功能更完善的窗口類,它們繼承了CWnd的屬性和方法,并提供了新的成員函數(shù)(消息處理函數(shù)、虛擬函數(shù)、等等)。

            常用的窗口類及其層次關(guān)系見圖1-1。

                1. 在MFC下創(chuàng)建一個窗口對象

                   

            MFC下創(chuàng)建一個窗口對象分兩步,首先創(chuàng)建MFC窗口對象,然后創(chuàng)建對應(yīng)的Windows窗口。在內(nèi)存使用上,MFC窗口對象可以在棧或者堆(使用new創(chuàng)建)中創(chuàng)建。具體表述如下:

            • 創(chuàng)建MFC窗口對象。通過定義一個CWnd或其派生類的實(shí)例變量或者動態(tài)創(chuàng)建一個MFC窗口的實(shí)例,前者在棧空間創(chuàng)建一個MFC窗口對象,后者在堆空間創(chuàng)建一個MFC窗口對象。

               

            • 調(diào)用相應(yīng)的窗口創(chuàng)建函數(shù),創(chuàng)建Windows窗口對象。

               

            例如:在前面提到的AppWizard產(chǎn)生的源碼中,有CMainFrame(派生于CMDIFrame(SDI)或者CMDIFrameWnd(MDI))類。它有兩個成員變量定義如下:

            CToolBar m_wndToolBar;

            CStatusBar m_wndStatusBar;

            當(dāng)創(chuàng)建CMainFrame類對象時,上面兩個MFC Object也被構(gòu)造。

            CMainFrame還有一個成員函數(shù)

            OnCreate(LPCREATESTRUCT lpCreateStruct),

            它的實(shí)現(xiàn)包含如下一段代碼,調(diào)用CToolBar和CStatusBar的成員函數(shù)Create來創(chuàng)建上述兩個MFC對象對應(yīng)的工具欄HWND窗口和狀態(tài)欄HWND窗口:

            int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

            {

            if (!m_wndToolBar.Create(this) ||

            !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

            {

            TRACE0("Failed to create toolbar\n");

            return -1; // fail to create

            }

            if (!m_wndStatusBar.Create(this) ||

            !m_wndStatusBar.SetIndicators(indicators,

            sizeof(indicators)/sizeof(UINT)))

            {

            TRACE0("Failed to create status bar\n");

            return -1; // fail to create

            }

            }

            關(guān)于工具欄、狀態(tài)欄將在后續(xù)有關(guān)章節(jié)作詳細(xì)討論。

            在MFC中,還提供了一種動態(tài)創(chuàng)建技術(shù)。動態(tài)創(chuàng)建的過程實(shí)際上也如上所述分兩步,只不過MFC使用這個技術(shù)是由框架自動地完成整個過程的。通常框架窗口、文檔框架窗口、視使用了動態(tài)創(chuàng)建。介于MFC的結(jié)構(gòu),CFrameWnd和CView及其派生類的實(shí)例即使不使用動態(tài)創(chuàng)建,也要用new在堆中分配。理由見窗口的銷毀(2.2.5節(jié))。

            至于動態(tài)創(chuàng)建技術(shù),將在下一章具體討論。

            在Windows窗口的創(chuàng)建過程中,將發(fā)送一些消息,如:

            在創(chuàng)建了窗口的非客戶區(qū)(Nonclient area)之后,發(fā)送消息WM_NCCREATE;

            在創(chuàng)建了窗口的客戶區(qū)(client area)之后,發(fā)送消息WM_CREATE;

            窗口的窗口過程在窗口顯示之前收到這兩個消息。

            如果是子窗口,在發(fā)送了上述兩個消息之后,還給父窗口發(fā)送WM_PARENATNOTIFY消息。其他類或風(fēng)格的窗口可能發(fā)送更多的消息,具體參見SDK開發(fā)文檔。

                1. MFC窗口的使用

                   

                  MFC提供了大量的窗口類,其功能和用途各異。程序員應(yīng)該選擇哪些類來使用,以及怎么使用他們呢?

                  直接使用MFC提供的窗口類或者先從MFC窗口類派生一個新的C++類然后使用它,這些在通常情況下都不需要程序員提供窗口注冊的代碼。是否需要派生新的C++類,視MFC已有的窗口類是否能滿足使用要求而定。派生的C++類繼承了基類的特性并改變或擴(kuò)展了它的功能,例如增加或者改變對消息、事件的特殊處理等。

                  主要使用或繼承以下一些MFC窗口類(其層次關(guān)系圖見圖1-1):

                  框架類CFrameWnd,CMdiFrameWnd;

                  文檔框架CMdiChildWnd;

                  視圖CView和CView派生的有特殊功能的視圖如:列表CListView,編輯CEditView,樹形列表CTreeView,支持RTF的CRichEditView,基于對話框的視CFormView等等。

                  對話框CDialog。

                  通常,都要從這些類派生應(yīng)用程序的框架窗口和視窗口或者對話框。

                  工具條CToolBar

                  狀態(tài)條CStatusBar

                  其他各類控制窗口,如列表框CList,編輯框CEdit,組合框CComboBox,按鈕Cbutton等。

                  通常,直接使用這些類。

                2. 在MFC下窗口的銷毀

                   

            窗口對象使用完畢,應(yīng)該銷毀。在MFC下,一個窗口對象的銷毀包括HWND窗口對象的銷毀和MFC窗口對象的銷毀。一般情況下,MFC編程框架自動地處理了這些。

            (1)對CFrameWnd和CView的派生類

            這些窗口的關(guān)閉導(dǎo)致銷毀窗口的函數(shù)DestroyWindow被調(diào)用。銷毀Windows窗口時,MFC框架調(diào)用的最后一個成員函數(shù)是OnNcDestroy函數(shù),該函數(shù)負(fù)責(zé)Windows清理工作,并在最后調(diào)用虛擬成員函數(shù)PostNcDestroy。CFrameWnd和CView的PostNcDestroy調(diào)用delete this刪除自身這個MFC窗口對象。

            所以,對這些窗口,如前所述,應(yīng)在堆(Heap)中分配,而且,不要對這些對象使用delete操作。

            (2)對Windows Control窗口

            在它們的析構(gòu)函數(shù)中,將調(diào)用DestroyWidnow來銷毀窗口。如果在棧中分配這樣的窗口對象,則在超出作用范圍的時候,隨著析構(gòu)函數(shù)的調(diào)用,MFC窗口對象和它的Windows window對象都被銷毀。如果在堆(Heap)中分配,則顯式調(diào)用delete操作符,導(dǎo)致析構(gòu)函數(shù)的調(diào)用和窗口的銷毀。

            所以,這種類型的窗口應(yīng)盡可能在棧中分配,避免用額外的代碼來銷毀窗口。如前所述的CMainFrame的成員變量m_wndStatusBar和m_wndToolBar就是這樣的例子。

            (3)對于程序員直接從CWnd派生的窗口

            程序員可以在派生類中實(shí)現(xiàn)上述兩種機(jī)制之一,然后,在相應(yīng)的規(guī)范下使用。

            后面章節(jié)將詳細(xì)的討論應(yīng)用程序退出時關(guān)閉、清理窗口的過程。

              1. 設(shè)備描述表

                 

                1. 設(shè)備描述表概述

                   

            當(dāng)一個應(yīng)用程序使用GDI函數(shù)時,必須先裝入特定的設(shè)備驅(qū)動程序,然后為繪制窗口準(zhǔn)備設(shè)備描述表,比如指定線的寬度和顏色、刷子的樣式和顏色、字體、剪裁區(qū)域等等。不像其他Win32結(jié)構(gòu),設(shè)備描述表不能被直接訪問,只能通過系列Win32函數(shù)來間接地操作。

            如同Windows“窗口類”一樣,設(shè)備描述表也是一種Windows數(shù)據(jù)結(jié)構(gòu),用來描述繪制窗口所需要的信息。它定義了一個坐標(biāo)映射模式、一組GDI圖形對象及其屬性。這些GDI對象包括用于畫線的筆,繪圖、填圖的刷子,位圖,調(diào)色板,剪裁區(qū)域,及路徑(Path)。

            表2-2列出了設(shè)備描述表的結(jié)構(gòu)和各項(xiàng)缺省值,表2-3列出了設(shè)備描述表的類型,表2-4顯示設(shè)備描述表的類型。

            表2-2 設(shè)備描述表的結(jié)構(gòu)

            屬性

            缺省值

            Background color

            Background color setting from Windows Control Panel (typically, white)

            Background mode

            OPAQUE

            Bitmap

            None

            Brush

            WHITE_BRUSH

            Brush origin

            (0,0)

            Clipping region

            Entire window or client area with the update region clipped, as appropriate. Child and pop-up windows in the client area may also be clipped

            Palette

            DEFAULT_PALETTE

            Current pen position

            (0,0)

            Device origin

            Upper left corner of the window or the client area

            Drawing mode

            R2_COPYPEN

            Font

            SYSTEM_FONT (SYSTEM_FIXED_FONT for applications written to run with Windows versions 3.0 and earlier)

            Intercharacter spacing

            0

            Mapping mode

            MM_TEXT

            Pen

            BLACK_PEN

            Polygon-fill mode

            ALTERNATE

            Stretch mode

            BLACKONWHITE

            Text color

            Text color setting from Control Panel (typically, black)

            Viewport extent

            (1,1)

            Viewport origin

            (0,0)

            Window extent

            (1,1)

            Window origin

            (0,0)

             

            表2-3 設(shè)備描述表的分類

            Display

            顯示設(shè)備描述表,提供對視頻顯示設(shè)備上的繪制操作的支持

            Printer

            打印設(shè)備描述表,提供對打印機(jī)、繪圖儀設(shè)備上的繪制操作的支持

            Memory

            內(nèi)存設(shè)備描述表,提供對位圖操作的支持

            Information

            信息設(shè)備描述表,提供對操作設(shè)備信息獲取的支持

            表2-3中的顯示設(shè)備描述表又分三種類型,如表2-4所示。

            表2-4 顯示設(shè)備描述表的分類

            名稱

            特點(diǎn)

            功能

            Class Device

            Contexts

            提供對Win16的向后兼容

             

            Common

            Device

            Contexts

            在Windows系統(tǒng)的高速緩沖區(qū),數(shù)量有限

            Applicaion獲取設(shè)備描述表時,Windows用缺省值初始化該設(shè)備描述表,Application使用它完成繪制操作,然后釋放

            Private

            Device

            Contexts

            沒有數(shù)量限制,用完不需釋放一次獲取,多次使用

            多次使用過程中,每次設(shè)備描述表屬性的任何修改或變化都會被保存,以支持快速繪制

             

            (1)使用設(shè)備描述表的步驟

            要使用設(shè)備描述表,一般有如下步驟:

            • 獲取或者創(chuàng)建設(shè)備描述表;

               

            • 必要的話,改變設(shè)備描述表的屬性;

               

            • 使用設(shè)備描述表完成繪制操作;

               

            • 釋放或刪除設(shè)備描述表。

               

            Common設(shè)備描述表通過::GetDC,::GetDCEx,::BeginPaint來獲得一個設(shè)備描述表,用畢,用::ReleaseDC或::EndPaint釋放設(shè)備描述表;

            Printer設(shè)備描述表通過::CreateDC創(chuàng)建設(shè)備描述表,用::DeleteDC刪除設(shè)備描述表。

            Memory設(shè)備描述表通過::CreateCompatibleDC創(chuàng)建設(shè)備描述表,用::DeleteDC刪除。

            Information設(shè)備描述表通過::CreateIC創(chuàng)建設(shè)備描述表,用::DeleteDC刪除。

            (2)改變設(shè)備描述表屬性的途徑

            要改變設(shè)備描述表的屬性,可通過以下途徑:

            用::SelectObject選入新的除調(diào)色板以外的GDI Object到設(shè)備描述表中;

            對于調(diào)色板,使用::SelectPalette函數(shù)選入邏輯調(diào)色板,并使用::RealizePalette把邏輯調(diào)色板的入口映射到物理調(diào)色板中。

            用其他API函數(shù)改變其他屬性,如::SetMapMode改變映射模式。

                1. 設(shè)備描述表在MFC中的實(shí)現(xiàn)

                   

            MFC提供了CDC類作為設(shè)備描述表類的基類,它封裝了Windows的HDC設(shè)備描述表對象和相關(guān)函數(shù)。

            1. CDC類

               

              CDC類包含了各種類型的Windows設(shè)備描述表的全部功能,封裝了所有的Win32 GDI 函數(shù)和設(shè)備描述表相關(guān)的SDK函數(shù)。在MFC下,使用CDC的成員函數(shù)來完成所有的窗口繪制工作。

              CDC 類的結(jié)構(gòu)示意圖2-2所示。

              CDC類有兩個成員變量:m_hDC,m_hAttribDC,它們都是Windows設(shè)備描述表句柄。CDC的成員函數(shù)作輸出操作時,使用m_Hdc;要獲取設(shè)備描述表的屬性時,使用m_hAttribDC。

              在創(chuàng)建一個CDC類實(shí)例時,缺省的m_hDC等于m_hAttribDC。如果需要的話,程序員可以分別指定它們。例如,MFC框架實(shí)現(xiàn)CMetaFileDC類時,就是如此:CMetaFileDC從物理設(shè)備上讀取設(shè)備信息,輸出則送到元文件(metafile)上,所以m_hDC和m_hAttribDC是不同的,各司其責(zé)。還有一個類似的例子:打印預(yù)覽的實(shí)現(xiàn),一個代表打印機(jī)模擬輸出,一個代表屏幕顯示。

              CDC封裝::SelectObject(HDC hdc,HGDIOBJECT hgdiobject)函數(shù)時,采用了重載技術(shù),即它針對不同的GDI對象,提供了名同而參數(shù)不同的成員函數(shù):

              SelectObject(CPen *pen)用于選入筆;

              SelectObject(CBitmap* pBitmap)用于選入位圖;

              SelectObject(CRgn *pRgn)用于選入剪裁區(qū)域;

              SelectObject(CBrush *pBrush)用于選入刷子;

              SelectObject(CFont *pFont)用于選入字體;

              至于調(diào)色板,使用SelectPalette(CPalette *pPalette,BOOL bForceBackground )選入調(diào)色板到設(shè)備描述表,使用RealizePalletter()實(shí)現(xiàn)邏輯調(diào)色板到物理調(diào)色板的映射。

            2. 從CDC派生出功能更具體的設(shè)備描述表

               

            從CDC 派生出四個功能更具體的設(shè)備描述表類。層次如圖2-3所示。

            下面,分別討論派生出的四種設(shè)備描述表。

            • CCientDC

               

            代表窗口客戶區(qū)的設(shè)備描述表。其構(gòu)造函數(shù)CClientDC(CWnd *pWin)通過::GetDC獲取指定窗口的客戶區(qū)的設(shè)備描述表HDC,并且使用成員函數(shù)Attach把它和CClientDC對象捆綁在一起;其析構(gòu)函數(shù)使用成員函數(shù)Detach把設(shè)備描述表句柄HDC分離出來,并調(diào)用::ReleaseDC釋放設(shè)備描述表HDC。

            • CPaintDC

               

            僅僅用于響應(yīng)WM_PAINT消息時繪制窗口,因?yàn)樗臉?gòu)造函數(shù)調(diào)用了::BeginPaint獲取設(shè)備描述表HDC,并且使用成員函數(shù)Attach把它和CPaintDC對象捆綁在一起;析構(gòu)函數(shù)使用成員函數(shù)Detach把設(shè)備描述表句柄HDC分離出來,并調(diào)用::EndPaint釋放設(shè)備描述表HDC,而::BeginPaint和::EndPaint僅僅在響應(yīng)WM_PAINT時使用。

            • CMetaFileDC

               

            用于生成元文件。

            • CWindowDC

               

            代表整個窗口區(qū)(包括非客戶區(qū))的設(shè)備描述表。其構(gòu)造函數(shù)CWindowDC(CWnd *pWin)通過::GetWindowDC獲取指定窗口的客戶區(qū)的設(shè)備描述表HDC,并使用Attach把它和CWindowDC對象捆綁在一起;其析構(gòu)函數(shù)使用Detach把設(shè)備描述表HDC分離出來,調(diào)用::ReleaseDC釋放設(shè)備描述表HDC。

                1. MFC設(shè)備描述表類的使用

                   

            1. 使用CPaintDC、CClientDC、CWindowDC的方法

               

              首先,定義一個這些類的實(shí)例變量,通常在棧中定義。然后,使用它。

              例如,MFC中CView對WM_PAINT消息的實(shí)現(xiàn)方法如下:

              void CView::OnPaint()

              {

              // standard paint routine

              CPaintDC dc(this);

              OnPrepareDC(&dc);

              OnDraw(&dc);

              }

              在棧中定義了CPaintDC類型的變量dc,隨著構(gòu)造函數(shù)的調(diào)用獲取了設(shè)備描述表;設(shè)備描述表使用完畢,超出其有效范圍就被自動地清除,隨著析構(gòu)函數(shù)的調(diào)用,其獲取的設(shè)備描述表被釋放。

              如果希望在堆中創(chuàng)建,例如

              CPaintDC *pDC;

              pDC = new CPaintDC(this)

              則在使用完畢時,用delete刪除pDC:

              delete pDC;

            2. 直接使用CDC

               

            需要注意的是:在生成CDC對象的時候,并不像它的派生類那樣,在構(gòu)造函數(shù)里獲取相應(yīng)的Windows設(shè)備描述表。最好不要使用::GetDC等函數(shù)來獲取一個設(shè)備描述表,而是創(chuàng)建一個設(shè)備描述表。其構(gòu)造函數(shù)如下:

            CDC::CDC()

            {

            m_hDC = NULL;

            m_hAttribDC = NULL;

            m_bPrinting = FALSE;

            }

            其析構(gòu)函數(shù)如下:

            CDC::~CDC()

            {

            if (m_hDC != NULL)

            ::DeleteDC(Detach());

            }

            在CDC析構(gòu)函數(shù)中,如果設(shè)備描述表句柄不空,則調(diào)用DeleteDC刪除它。這是直接使用CDC時最好創(chuàng)建Windows設(shè)備描述表的理由。如果設(shè)備描述表不是創(chuàng)建的,則應(yīng)該在析構(gòu)函數(shù)被調(diào)用前分離出設(shè)備描述表句柄并用::RealeaseDC釋放它,釋放后m_hDC為空,則在析構(gòu)函數(shù)調(diào)用時不會執(zhí)行::DeleteDC。當(dāng)然,不用擔(dān)心CDC的派生類的析構(gòu)函數(shù)調(diào)用CDC的析構(gòu)函數(shù),因?yàn)镃DC::~CDC()不是虛擬析構(gòu)函數(shù)。

            直接使用CDC的例子是內(nèi)存設(shè)備上下文,例如:

            CDC dcMem; //聲明一個CDC對象

            dcMem.CreateCompatibleDC(&dc); //創(chuàng)建設(shè)備描述表

            pbmOld = dcMem.SelectObject(&m_bmBall);//更改設(shè)備描述表屬性

            …//作一些繪制操作

            dcMem.SelectObject(pbmOld);//恢復(fù)設(shè)備描述表的屬性

            dcMem.DeleteDC(); //可以不調(diào)用,而讓析構(gòu)函數(shù)去刪除設(shè)備描述表

              1. GDI對象

                 

            在討論設(shè)備描述表時,已經(jīng)多次涉及到GDI對象。這里,需強(qiáng)調(diào)一下:GDI對象要選入Windows 設(shè)備描述表后才能使用;用畢,要恢復(fù)設(shè)備描述表的原GDI對象,并刪除該GDI對象。

            一般按如下步驟使用GDI對象:

            Create or get a GDI OBJECT hNewGdi;

            hOldGdi = ::SelectObject(hdc, hNewGdi)

            ……

            ::SelectObject(hdc, hOldGdi)

            ::DeleteObject(hNewGdi)

            先創(chuàng)建或得到一個GDI對象,然后把它選入設(shè)備描述表并保存它原來的GDI對象;用畢恢復(fù)設(shè)備描述表原來的GDI對象并刪除新創(chuàng)建的GDI對象。

            需要指出的是,如果hNewGdi是一個Stock GDI對象,可以不刪除(刪除也可以)。通過

            HGDIOBJ GetStockObject(

            int fnObject // type of stock object

            );

            來獲取Stock GDI對象。

            1. MFC GDI對象

               

              MFC用一些類封裝了Windows GDI對象和相關(guān)函數(shù),層次結(jié)構(gòu)如圖2-4所示:

              CGdiObject封裝了Windows GDI Object共有的特性。其派生類在繼承的基礎(chǔ)上,主要封裝了各類GDI的創(chuàng)建函數(shù)以及和具體GDI對象相關(guān)的操作。

              CGdiObject的構(gòu)造函數(shù)僅僅讓m_hObject為空。如果m_hObject不空,其析構(gòu)函數(shù)將刪除對應(yīng)的Windows GDI對象。MFC GDI對象和Windows GDI對象的關(guān)系如圖2-5所示。

            2. 使用MFC GDI類的使用

               

            首先創(chuàng)建GDI對象,可分一步或兩步創(chuàng)建。一步創(chuàng)建就是構(gòu)造MFC對象和Windows GDI對象一步完成;兩步創(chuàng)建則先構(gòu)造MFC對象,接著創(chuàng)建Windows GDI對象。然后,把新創(chuàng)建的GDI對象選進(jìn)設(shè)備描述表,取代原GDI對象并保存。最后,恢復(fù)原GDI對象。例如:

            void CMyView::OnDraw(CDC *pDC)

            {

            CPen penBlack; //構(gòu)造MFC CPen對象

            if (penBlack.CreatePen(PS_SOLID, RGB(0, 0, 0)))

            {

            CPen *pOldPen = pDC->SelectObject(&penBlack)); //選進(jìn)設(shè)備表,保存原筆

            pDC->SelectObject(pOldPen); //恢復(fù)原筆

            }else

            {

            }

            }

            和在SDK下有一點(diǎn)不同的是:這里沒有DeleteObject。因?yàn)閳?zhí)行完OnDraw后,棧中的penBlack被銷毀,它的析構(gòu)函數(shù)被調(diào)用,導(dǎo)致DeleteObject的調(diào)用。

            還有一點(diǎn)要說明:

            pDC->SelectObject(&penBlack)返回了一個CPen *指針,也就是說,它根據(jù)原來PEN的句柄創(chuàng)建了一個MFC CPen對象。這個對象是否需要刪除呢?不必要,因?yàn)樗且粋€臨時對象,MFC框架會自動地刪除它。當(dāng)然,在本函數(shù)執(zhí)行完畢把控制權(quán)返回給主消息循環(huán)之前,該對象是有效的。

            關(guān)于臨時對象及MFC處理它們的內(nèi)部機(jī)制,將在后續(xù)章節(jié)詳細(xì)討論。

            至此,Windows編程的核心概念:窗口、GDI界面(設(shè)備描述表、GDI對象等)已經(jīng)陳述清楚,特別揭示了MFC對這些概念的封裝機(jī)制,并簡明講述了與這些Windows Object對應(yīng)的MFC類的使用方法。還有其他Windows概念,可以參見SDK開發(fā)文檔。在MFC的實(shí)現(xiàn)上,基本上僅僅是對和這些概念相關(guān)的Win32函數(shù)的封裝。如果明白了MFC的窗口、GDI界面的封裝機(jī)制,其他就不難了。

            posted @ 2008-11-01 15:42 wrh 閱讀(1335) | 評論 (0)編輯 收藏

            系統(tǒng)理解Win32 API和MFC(下)
            作者: 溫昱
            作者主頁: lcspace.diy.163.com

            系統(tǒng)理解Win32 API和MFC(上)

            二、MFC的概念模型

            前面我們研究了WIN32 API的“領(lǐng)域模型”,對它有較全面的認(rèn)識。下面,對MFC概念模型的研究,我們把重點(diǎn)放在對app framework的研究上。
            app framework中的message響應(yīng)/傳遞機(jī)制是最重要的。而Hook機(jī)制和Message響應(yīng)/傳遞機(jī)制是密切相關(guān)的,后者以前者為基礎(chǔ)。

            1. Hook機(jī)制

            也許有些程序員只知道hook機(jī)制可以編寫很“牛”的應(yīng)用,孰不知MFC本身也是依靠hook機(jī)制的。

            從圖中看到,每個hook擁有一個指針隊(duì)列,每個指針指向一個稱為的HookProc函數(shù),HookProc將在合適的時機(jī)被OS調(diào)用執(zhí)行。hook是分不同種類的,其實(shí)正是hook的種類決定了它什么時機(jī)被OS調(diào)用執(zhí)行。提示,可以看一下“訂閱-發(fā)布”設(shè)計(jì)模式以助理解。

            2 MFC中Message響應(yīng)函數(shù)的安裝

            2.1 回憶API中Message響應(yīng)函數(shù)的安裝

            API中Message響應(yīng)函數(shù)的安裝,是由CreateWindow()實(shí)現(xiàn)的,它將window與一個windowClass聯(lián)系起來,而后者中記錄了Message響應(yīng)函數(shù)的指針。
            至于細(xì)節(jié),看一下如何用Win32 SDK或Win16 SDK寫程序就清楚了,其中 DefWindowProc()是API函數(shù),負(fù)責(zé)提供缺省的消息處理,所以,程序員只需要handle需要特殊處理的消息。

            int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)
            {
            WNDCLASS wndclass;
            ...
            wndclass.lpfnWndProc =WndProc;
            wndclass.lpszClassName = szWindowClass;
            ...
            RegisterClass(&wndclass);
            hWnd = CreateWindow( szWindowClass, ...);
            ...
            }
            LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
            {
            switch(message)
            {
            ...
            return;
            }
            return DefWindowProc(hwnd,message,wParam,lParam);
            }
            
            2.2 MFC中Message響應(yīng)函數(shù)的安裝

            MFC中Message響應(yīng)函數(shù)的安裝顯然更復(fù)雜,是在CWnd::CreateEx()被調(diào)用時完成的,其中還用到了Hook機(jī)制。

            我們可以先猜一下MFC是怎么做的。MFC支持massage map,使得對消息的響應(yīng)份散到多個message handler函數(shù)中,而不是API開發(fā)是那種集中式的消息處理函數(shù);所以,想必會有專門的代碼來負(fù)責(zé)“檢索message map table然后調(diào)用message handle”。message map是為了支持程序員處理他關(guān)心的特殊message的,那么缺省的message處理邏輯在哪里呢?答案是MFC創(chuàng)建window obj時是用的“預(yù)定義的窗口類”,自然已經(jīng)有了缺省的message處理函數(shù)。

            從圖中看到,CWnd有成員變量m_pfnSuper、成員變量m_hWnd、成員函數(shù)OnWndMsg()和成員函數(shù)DefWindowProc()。Wnd::OnWndMsg()負(fù)責(zé)“在message map中定義的message handle”能否處理到來的message,如果處理了要返回true;CWnd::DefWindowProc()負(fù)責(zé)對message缺省處理。
            執(zhí)行過程是,首先CWnd::CreateEx()被調(diào)用,window obj和window class被相應(yīng)建立,此時window class的WindowProc字段存儲了預(yù)定義的缺省處理函數(shù)的地址;由于有hook在監(jiān)聽窗口創(chuàng)建消息,所以注冊的hookProc()會被調(diào)用執(zhí)行,它將classWindow數(shù)據(jù)結(jié)構(gòu)的WindowProc字段備份到CWnd::m_pfnSuper,再用SetWindowLong()改寫classWindow數(shù)據(jù)結(jié)構(gòu)的WindowProc字段為::AfxWndProc()的地址。當(dāng)任何一個message到達(dá)時,::AfxWndProc()被調(diào)用,至于它的邏輯,聰明的你一定猜到了,先調(diào)用Wnd::OnWndMsg(),如果返回值為false,還要調(diào)用CWnd::DefWindowProc(),CWnd::m_pfnSuper指向的缺省處理邏輯,也會在CWnd::DefWindowProc()中被調(diào)用。
            提示,上面其實(shí)有多態(tài)情況發(fā)生。比如你可以在搜一下pWnd->WindowProc(nMsg, wParam, lParam); 另外,OnWndMsg和DefWindowProc都是CWnd類的虛擬函數(shù)。

            要是覺得不太好理解,最好在VC++里創(chuàng)建一個project實(shí)際跟蹤一下,下面是我跟蹤時調(diào)用棧映象的截圖。


            3. SubClass機(jī)制


            從圖中看到,SubClass機(jī)制以CWnd自身的m_pfnSuper為基礎(chǔ),和“MFC中Message響應(yīng)函數(shù)的安裝”很象。

            4.frame work中的主要相關(guān)類

            frame work中的主要相關(guān)類 就是 message route的候選人,正是它們的OnCmdMsg()共同完成了message route,形成了chain of responsability模式。

            5. frame work中的chain of responsability模式

            下圖是一個對象樹,注意消息會在縱向和橫向兩個方向傳播。


            消息在縱向方向上的傳遞,是在“上溯父類的massge map表”,MFC的message map完全是為了代替虛函數(shù)而采取的手段,而和message route無關(guān)。

            消息在橫向方向上的傳遞,才是message route,才是chain of responsability模式,由多個相關(guān)類的OnCmdMsg()共同完成。

            三、 總結(jié)
            從上面的討論不難發(fā)現(xiàn),MFC中用到了不少設(shè)計(jì)模式,如上面提到的chain of responsability模式、composite模式和“訂閱-發(fā)布”模式。上面的討論不僅有助于程序員全面掌握Win32 API和MFC,對architect設(shè)計(jì)architecture也有很大幫助。

            posted @ 2008-11-01 15:38 wrh 閱讀(349) | 評論 (0)編輯 收藏

            系統(tǒng)理解Win32 API和MFC(上)
            作者: 溫昱
            作者主頁: lcspace.diy.163.com

            Win32 API是微軟的操作系統(tǒng)Windows提供給開發(fā)人員的編程接口,它決定了我們開發(fā)的Windows應(yīng)用程序的能力。MFC是微軟為開發(fā)人員提供的類庫,在某種意義上是對Win32 API的封裝。本文試圖從全局角度對Win32 API和MFC進(jìn)行理解──給出二者的概念模型。
            本文使用UML描述概念模型。Win32 API本不是面向?qū)ο蟮模矣妹嫦驅(qū)ο蟮挠^點(diǎn)去理解它,無非是想表達(dá)其全局。
            本文參考了MSDN、相關(guān)書籍和網(wǎng)上的一些資料,在此一并感謝。

            一、Win32 API的概念模型

            Win32 API的object有3種:user obj,gdi obj,kernel obj。但是,如果一點(diǎn)不考慮OS本身的支持,就會在有些問題上疑惑,因此,我這里把“operation system負(fù)責(zé)將中斷封裝成message”加上。

            1、user obj、gdi obj、kernel obj、system 4者的關(guān)系

            由于是kernel obj部分負(fù)責(zé)將另外3者聯(lián)系起來,因此我們在下圖中直接深入到kernel obj部分內(nèi)部。

            從圖中看到,在內(nèi)存中運(yùn)行的,除了“負(fù)責(zé)將中斷封裝成message”的system支持部分,還有另外3類object:kernel obj、user obj和gdi obj,每個obj都有一個句柄handle與之對應(yīng)。其中,gdi obj建立了待開發(fā)的Windows 應(yīng)用和外部輸出設(shè)備的聯(lián)系,kernel obj中的file建立了內(nèi)存和永久存儲設(shè)備的聯(lián)系。具體說,內(nèi)存中的file從可以從硬盤上來,如果這個file是可執(zhí)行文件,它將生成module,module運(yùn)行起來就是process,process可以包含多條thread,而thread的運(yùn)行映象最終還是來自于file。thread是kernel obj中最重要的一個,因?yàn)橄㈥?duì)列就是thread擁有的,只有thread才能夠接受message。對gdi obj、urser obj和file的操作,也是發(fā)生在thread中的。所以書都講,process至少擁有一個thread。

            2、展開“system負(fù)責(zé)將中斷封裝成message”部分

            下面展開“system負(fù)責(zé)將中斷封裝成message”部分,盡早解除對“message到底是怎么形成的”的困惑。


            3、展開“gdi obj”部分

            開發(fā)人員可以通過gdi obj將app的信息反饋給User。

            從圖中看到,gdi obj有8種,其中7種為:bmp,brush,pen,region,font,palette,path。另一種比較特殊的是DC,它可以被理解為一種容器,程序員通過調(diào)用SelectPallette()將pallte放入容器,通過調(diào)用BeginPath()和EndPath()將path放入容器,其它5種gdi obj,是通過調(diào)用SelectObject()放入容器的。DC又具體分為4種,其中DisplayDC就是最常用的用來支持我們“畫Window”的DC。 另外,如果覺得不好理解,請參考composite設(shè)計(jì)模式。

            4、展開user obj部分

            4.1 第1次迭代

            window在Windows應(yīng)用開發(fā)中占有重要地位。

            從圖中看到,window可分為3種:desktop,top-level window,child window。所有window被OS組織成tree,有專門的數(shù)據(jù)結(jié)構(gòu)來管理。desktop就是樹根,desktop的子節(jié)點(diǎn)是top-level window,top-level window的子節(jié)點(diǎn)是child window,child window仍然可以有子節(jié)點(diǎn),同樣歸屬于child window。tree數(shù)據(jù)結(jié)構(gòu)中還記錄了4種重要信息,是4種指針:parent指針、child指針、brother指針、owner指針。這樣,從任何一個window就能很容易地找到其它window了。

            好了,暫且得到 window = desktop + topLevel + child 的結(jié)論,看看全局先。畢竟,一步到位有時候并不好。
            從圖中看到,window確實(shí)占有重要地位。從邏輯是講,thread是window的擁有者;但是,所有window一起決定了屏幕看起來是上面樣子,何況點(diǎn)擊任何一個window都會使window得相互覆蓋關(guān)系發(fā)生變化,對所用window進(jìn)行統(tǒng)一管理是必須的,所以O(shè)S又不得不統(tǒng)一用window tree來管理window,反映復(fù)雜的window關(guān)系。每個window都必須有一個且只能有一個客戶區(qū),還可能有一個title bar。

             

            再來看看CreateWindow()函數(shù)的interface spec透露了哪些信息。

             


            從圖中看到,CreateWindow()負(fù)責(zé)為window建立與窗口類的聯(lián)系。每個window都有一個窗口類與之對應(yīng),而一個窗口類可以對應(yīng)多個window。窗口類中記錄了窗口函數(shù)和菜單等資源信息,而由file生成的module正是窗口函數(shù)和資源的老家。

             

            4.2 第2次迭代

            考察消息種類。

            從圖中看到,每個message都是發(fā)送給某個window的。注意,msg可由SYS代碼產(chǎn)生,也可以由API函數(shù)產(chǎn)生。

            進(jìn)一步考察window,深入topLevel和child。


            從圖中看到,OVERLAPPED風(fēng)格的window是top-level window的一種,而另一種POPUP風(fēng)格的window從本質(zhì)上(行為上)是特殊的一種OVERLAPPED風(fēng)格的window,雖然我們從coding的角度常常不這么認(rèn)為。

            還是不好,因?yàn)楫?dāng)我們調(diào)用CreateWindow() API函數(shù)時,明明感覺CHILD、OVERLAPPED、POPUP是“window style”。我再畫一張圖。

            從圖中看到,control必須是CHILD風(fēng)格的,dialog必須是POPUP風(fēng)格的,而一般性的window卻可以是任意風(fēng)格的。

            4.3 第3次迭代

            總結(jié)user obj:


            CreateDialog()函數(shù)示意:

            從圖中看到,CreateDialog()和CreateWindow()最大的區(qū)別就是,它有對話框模板支持方便地定制dialog界面。注意,Dialog是特殊的window,窗口類它一定也是有的。

            posted @ 2008-11-01 15:37 wrh 閱讀(208) | 評論 (0)編輯 收藏
            1.檢測程序中的括號是否匹配

              把光標(biāo)移動到需要檢測的括號(如大括號{}、方括號[]、圓括號()和尖括號<>)前面,鍵入快捷鍵“Ctrl+]”。如果括號匹配正確,光標(biāo)就跳到匹配的括號處,否則光標(biāo)不移動,并且機(jī)箱喇叭還會發(fā)出一聲警告聲。

              2.查看一個宏(或變量、函數(shù))的宏定義

              把光標(biāo)移動到你想知道的一個宏上,就比如說最常見的DECLARE_MAP_MESSAGE上按一下F12(或右鍵菜單中的Go To Defition Of …),如果沒有建立Browse files,會出現(xiàn)提示對話框,確定,然后就會跳到定義那些東西的地方。

              相當(dāng)可喜的是,它也可以看到Microsoft定義的系統(tǒng)宏,非常good.

              3.格式化一段亂七八糟的源代碼

              選中那段源代碼,按ATL+F8。

              4.在編輯狀態(tài)下發(fā)現(xiàn)成員變量或函數(shù)不能顯示

              刪除該項(xiàng)目擴(kuò)展名為.ncb文件,重新打開該項(xiàng)目。

              5.如何整理ClassView視圖中大量的類

              可以在classview 視圖中右鍵新建文件夾(new folder),再把具有相近性質(zhì)的類拖到對應(yīng)的文件夾中,使整個視圖看上去清晰明了.

              6.定位預(yù)處理指定

              在源文件中定位光標(biāo)到對稱的#if, #endif,使用Ctrl+K.

              7.如何添加系統(tǒng)中Lib到當(dāng)前項(xiàng)目

              在Project | Settings | Link | Object/library modules:輸入Lib名稱,不同的Lib之間用空格格開.

              8.如何添加系統(tǒng)中的頭文件(.h)到當(dāng)前項(xiàng)目.

              #include ,告訴編譯到VC系統(tǒng)目錄去找;使用#include "FileName.h",告訴編譯在當(dāng)前目錄找.

              9.如何在Studio使用匯編調(diào)試

              在WorkBench的Debugger狀態(tài)下按CTRL+F7.

              10.怎樣處理ClassZiard找不到的系統(tǒng)消息

              如果要在ClassWizard中處理WM_NCHITTEST等系統(tǒng)消息,請?jiān)贑lassWizard中Class Info頁中將Message filter改為Window就有了.

              11.如何干凈的刪除一個類

              先從Workspace中的FileView中刪除對應(yīng)的.h和.cpp文件,再關(guān)閉項(xiàng)目,從實(shí)際的文件夾中刪除對應(yīng)的.h和.cpp文件與.clw文件。

              12.在Studio中快速切換兩個文件

              有時,我們需要在最近使用的兩個文件中快速切換,換Ctrl+F6。這在兩個文件不相今的時候就有用的.

              13.取得源程序預(yù)處理后的結(jié)果:

              在Studio里,可以在->PROJECT-> SETTINGS->C/C++->Project Options中,在最后加上 /P /EP這兩個編譯開關(guān)即可做到"只進(jìn)行預(yù)處理".就可以了。編譯以后就可以在源程序目錄中發(fā)現(xiàn)“文件名.I ”的文本文件。這就是預(yù)處理后的結(jié)果。

              (注意注:區(qū)分大小定,請用大定/P)

              14.在Debug模式中查看WINAPI調(diào)用后的返回值:

              很簡單,且實(shí)用:在watch中加入@hr,err。在CSDN的文檔中心有一篇講得更細(xì),請參考。

              15.產(chǎn)生指定源程序文件的匯編代碼:

              從IDE菜單的Project->Setting打開項(xiàng)目設(shè)置,按如下文件做:

              1.先在左邊選擇指定文件,可以多選。

              2. 在右邊的C++屬性頁中,在category中選擇List Files,接著在下面的List Files Type中選擇Assembly and source code(或選擇其它),最后在List File Name中輸入在個C/C++源文件產(chǎn)生的相應(yīng)的匯編代碼的文件。

              3.編譯整個工程。

              16.手工編譯純資源成dll:

              Rc.exe /v data.rc
              Cvtres.exe /machine:ix86 data.res
              Link /SUBSYSTEM:WINDOWS /DLL /NOENTRY data.res ;編譯成DLL文件

              這種方式創(chuàng)建的DLL是最小的,比起你用Win 32 Dynamic Libray等產(chǎn)生的更小。

              17:怎樣快速生成一個與現(xiàn)有項(xiàng)目除了項(xiàng)目名外完全相同的新項(xiàng)目?

              利用File菜單下生成新項(xiàng)目中的Custom AppWizard ,選擇 An existing Project ,然后選擇現(xiàn)有項(xiàng)目的項(xiàng)目文件名(*.dsp)Finish,編譯后就生成一個可以生成與現(xiàn)有項(xiàng)目相同但可以重新取名的項(xiàng)目的AppWizard。你可以象用MFC AppWizard一樣用它。如果不想用了,可以在VC 安裝目錄下Common\MSDev98\Template目錄中刪除該Wizard中.awx和 .pdb文件。

              18:如果想把整個項(xiàng)目拷貝到軟盤,那些文件可以刪掉?

              除了項(xiàng)目文件夾中debug文件夾可以刪除外,.ncb,.clw,.opt 等文件也可以刪除,這些文件Rebuilt all后可以重新生成。

              附:VC項(xiàng)目文件說明

              .dsp 項(xiàng)目參數(shù)配置文件,這個文件太重要,重點(diǎn)保護(hù)對象。.

              .dsw 工作區(qū)文件,重要性一般,因?yàn)樗畔⒉晃遥菀谆謴?fù)。

              以下文件在項(xiàng)目中是可丟棄的,有些文件刪除后,VC會自動生成的。

              .clw ClassWizard信息文件,實(shí)際上是INI文件的格式,有興趣可以研究一下.有時候ClassWizard出問題,手工修改CLW文件可以解決.如果此文件不存在的話,每次用ClassWizard的時候繪提示你是否重建.

              .ncb 無編譯瀏覽文件(no compile browser)。當(dāng)自動完成功能出問題時可以刪除此文件。build后會自動生成。

              .opt 工程關(guān)于開發(fā)環(huán)境的參數(shù)文件。如工具條位置等信息;(可丟棄)

              .aps (AppStudio File),資源輔助文件,二進(jìn)制格式,一般不用去管他.

              .plg 是編譯信息文件,編譯時的error和warning信息文件(實(shí)際上是一個html文件),一般用處不大.在Tools->Options里面有個選項(xiàng)可以控制這個文件的生成.

              .hpj (Help Project)是生成幫助文件的工程,用microsfot Help Compiler可以處理.

              .mdp (Microsoft DevStudio Project)是舊版本的項(xiàng)目文件,如果要打開此文件的話,會提示你是否轉(zhuǎn)換成新的DSP格式.

              .bsc 是用于瀏覽項(xiàng)目信息的,如果用Source Brower的話就必須有這個文件.如果不用這個功能的話,可以在Project Options里面去掉Generate Browse Info File,可以加快編譯速度.

              .map 是執(zhí)行文件的映像信息紀(jì)錄文件,除非對系統(tǒng)底層非常熟悉,這個文件一般用不著.

              .pch (Pre-Compiled File)是預(yù)編譯文件,可以加快編譯速度,但是文件非常大.

              .pdb (Program Database)記錄了程序有關(guān)的一些數(shù)據(jù)和調(diào)試信息,在調(diào)試的時候可能有用.

              .exp 只有在編譯DLL的時候才會生成,記錄了DLL文件中的一些信息.一般也沒什么用.

            posted @ 2008-10-26 09:25 wrh 閱讀(190) | 評論 (0)編輯 收藏

            VC 中的定時

            VC中提供了很多關(guān)于時間操作的函數(shù),編寫程序時我們可以跟據(jù)定時的不同精度要求選擇不同的時間函數(shù)來完成定時和計(jì)時操作。
              
                 方式一:VC中的WM_TIMER消息映射能進(jìn)行簡單的時間控制。首先調(diào)用函數(shù)SetTimer()設(shè)置定時間隔,如SetTimer(0,200,NULL)即為設(shè)置200ms的時間間隔。然后在應(yīng)用程序中增加定時響應(yīng)函數(shù) OnTimer(),并在該函數(shù)中添加響應(yīng)的處理語句,用來完成到達(dá)定時時間的操作。這種定時方法非常簡單,可以實(shí)現(xiàn)一定的定時功能,但其定時功能如同Sleep()函數(shù)的延時功能一樣,精度非常低,最小計(jì)時精度僅為18ms。CPU占用低,且定時器消息在多任務(wù)操作系統(tǒng)中的優(yōu)先級很低,不能得到及時響應(yīng),往往不能滿足實(shí)時控制環(huán)境下的應(yīng)用。只可以用來實(shí)現(xiàn)諸如位圖的動態(tài)顯示等對定時精度要求不高的情況。

              方式二:VC中使用sleep()函數(shù)實(shí)現(xiàn)延時,它的單位是ms,如延時2秒,用sleep(2000)。精度非常低,最小計(jì)時精度僅為30ms,用sleep函數(shù)的不利處在于延時期間不能處理其他的消息,如果時間太長,就好象死機(jī)一樣,CPU占用率非常高,只能用于要求不高的延時程序中。

              方式三:利用COleDateTime類和COleDateTimeSpan類結(jié)合WINDOWS的消息處理過程來實(shí)現(xiàn)秒級延時。以下是實(shí)現(xiàn)2秒的延時代碼:

                 COleDateTime      start_time = COleDateTime::GetCurrentTime();
                 COleDateTimeSpan end_time= COleDateTime::GetCurrentTime()-start_time;
                 while(end_time.GetTotalSeconds()< 2) //實(shí)現(xiàn)延時2秒
                {
                         MSG   msg;
                         GetMessage(&msg,NULL,0,0);
                         TranslateMessage(&msg);
                         DispatchMessage(&msg);
                         
                        //以上四行是實(shí)現(xiàn)在延時或定時期間能處理其他的消息,
                 //雖然這樣可以降低CPU的占有率,
                        //但降低了延時或定時精度,實(shí)際應(yīng)用中可以去掉。
                        end_time = COleDateTime::GetCurrentTime()-start_time;
                 }//這樣在延時的時候我們也能夠處理其他的消息。      

              方式四:在精度要求較高的情況下,VC中可以利用GetTickCount()函數(shù),該函數(shù)的返回值是 DWORD型,表示以ms為單位的計(jì)算機(jī)啟動后經(jīng)歷的時間間隔。精度比WM_TIMER消息映射高,在較短的定時中其計(jì)時誤差為15ms,在較長的定時中其計(jì)時誤差較低,如果定時時間太長,就好象死機(jī)一樣,CPU占用率非常高,只能用于要求不高的延時程序中。下列代碼可以實(shí)現(xiàn)50ms的精確定時:
                  DWORD dwStart = GetTickCount();
                  DWORD dwEnd   = dwStart;
                  do
                  {
                     dwEnd = GetTickCount() - dwStart;
                  }while(dwEnd <50);
            為使GetTickCount()函數(shù)在延時或定時期間能處理其他的消息,可以把代碼改為:
                  DWORD dwStart = GetTickCount();
                  DWORD dwEnd   = dwStart;
                  do
                  {
                         MSG   msg;
                         GetMessage(&msg,NULL,0,0);
                         TranslateMessage(&msg);
                         DispatchMessage(&msg);
                         dwEnd = GetTickCount()-dwStart;
                  }while(dwEnd <50);
            雖然這樣可以降低CPU的占有率,并在延時或定時期間也能處理其他的消息,但降低了延時或定時精度。

              方式五:與GetTickCount()函數(shù)類似的多媒體定時器函數(shù)DWORD timeGetTime(void),該函數(shù)定時精度為ms級,返回從Windows啟動開始經(jīng)過的毫秒數(shù)。微軟公司在其多媒體Windows中提供了精確定時器的底層API持,利用多媒體定時器可以很精確地讀出系統(tǒng)的當(dāng)前時間,并且能在非常精確的時間間隔內(nèi)完成一個事件、函數(shù)或過程的調(diào)用。不同之處在于調(diào)用DWORD timeGetTime(void) 函數(shù)之前必須將 Winmm.lib 和 Mmsystem.h 添加到工程中,否則在編譯時提示DWORD timeGetTime(void)函數(shù)未定義。由于使用該函數(shù)是通過查詢的方式進(jìn)行定時控制的,所以,應(yīng)該建立定時循環(huán)來進(jìn)行定時事件的控制。

              方式六:使用多媒體定時器timeSetEvent()函數(shù),該函數(shù)定時精度為ms級。利用該函數(shù)可以實(shí)現(xiàn)周期性的函數(shù)調(diào)用。函數(shù)的原型如下:
                  MMRESULT timeSetEvent( UINT uDelay,
                                          UINT uResolution,
                                          LPTIMECALLBACK lpTimeProc,
                                          WORD dwUser,
                                          UINT fuEvent )
              該函數(shù)設(shè)置一個定時回調(diào)事件,此事件可以是一個一次性事件或周期性事件。事件一旦被激活,便調(diào)用指定的回調(diào)函數(shù),成功后返回事件的標(biāo)識符代碼,否則返回NULL。函數(shù)的參數(shù)說明如下:
                  uDelay:以毫秒指定事件的周期。
                  Uresolution:以毫秒指定延時的精度,數(shù)值越小定時器事件分辨率越高。缺省值為1ms。
                  LpTimeProc:指向一個回調(diào)函數(shù)。
                  DwUser:存放用戶提供的回調(diào)數(shù)據(jù)。
                  FuEvent:指定定時器事件類型:
                  TIME_ONESHOT:uDelay毫秒后只產(chǎn)生一次事件
                  TIME_PERIODIC :每隔uDelay毫秒周期性地產(chǎn)生事件。      

              具體應(yīng)用時,可以通過調(diào)用timeSetEvent()函數(shù),將需要周期性執(zhí)行的任務(wù)定義在LpTimeProc回調(diào)函數(shù)中(如:定時采樣、控制等),從而完成所需處理的事件。需要注意的是,任務(wù)處理的時間不能大于周期間隔時間。另外,在定時器使用完畢后,應(yīng)及時調(diào)用timeKillEvent()將之釋放。

              方式七:對于精確度要求更高的定時操作,則應(yīng)該使用QueryPerformanceFrequency()和 QueryPerformanceCounter()函數(shù)。這兩個函數(shù)是VC提供的僅供Windows 95及其后續(xù)版本使用的精確時間函數(shù),并要求計(jì)算機(jī)從硬件上支持精確定時器。

                 QueryPerformanceFrequency()函數(shù)和QueryPerformanceCounter()函數(shù)的原型如下:
                  BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
                  BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount);
              數(shù)據(jù)類型ARGE_INTEGER既可以是一個8字節(jié)長的整型數(shù),也可以是兩個4字節(jié)長的整型數(shù)的聯(lián)合結(jié)構(gòu),其具體用法根據(jù)編譯器是否支持64位而定。該類型的定義如下:
                  typedef union _LARGE_INTEGER
                  {
                      struct
                      {
                         DWORD LowPart ;// 4字節(jié)整型數(shù)
                         LONG HighPart;// 4字節(jié)整型數(shù)
                      };
                      LONGLONG QuadPart ;// 8字節(jié)整型數(shù)
                      
                   }LARGE_INTEGER ;
              
                 在進(jìn)行定時之前,先調(diào)用QueryPerformanceFrequency()函數(shù)獲得機(jī)器內(nèi)部定時器的時鐘頻率,然后在需要嚴(yán)格定時的事件發(fā)生之前和發(fā)生之后分別調(diào)用QueryPerformanceCounter()函數(shù),利用兩次獲得的計(jì)數(shù)之差及時鐘頻率,計(jì)算出事件經(jīng)歷的精確時間。下列代碼實(shí)現(xiàn)1ms的精確定時:
                  LARGE_INTEGER litmp;
                  LONGLONG QPart1,QPart2;
                  double dfMinus, dfFreq, dfTim;
                  QueryPerformanceFrequency(&litmp);
                  dfFreq = (double)litmp.QuadPart;// 獲得計(jì)數(shù)器的時鐘頻率
                  QueryPerformanceCounter(&litmp);
                  QPart1 = litmp.QuadPart;// 獲得初始值
                  do
                  {
                     QueryPerformanceCounter(&litmp);
                     QPart2 = litmp.QuadPart;//獲得中止值
                     dfMinus = (double)(QPart2-QPart1);
                     dfTim = dfMinus / dfFreq;// 獲得對應(yīng)的時間值,單位為秒
                  }while(dfTim<0.001);

            posted @ 2008-10-25 09:15 wrh 閱讀(1597) | 評論 (0)編輯 收藏


            VC定時器 SetTimer 怎么用阿
            [此問題的推薦答案]
            SetTimer函數(shù)的用法
            1 )用WM_TIMER來設(shè)置定時器

            先請看SetTimer這個API函數(shù)的原型

            UINT_PTR SetTimer(
            HWND hWnd, // 窗口句柄
            UINT_PTR nIDEvent, // 定時器ID,多個定時器時,可以通過該ID判斷是哪個定時器
            UINT uElapse, // 時間間隔,單位為毫秒
            TIMERPROC lpTimerFunc // 回調(diào)函數(shù)
            );

            例如
            SetTimer(m_hWnd,1,1000,NULL); //一個1秒觸發(fā)一次的定時器
            在MFC程序中SetTimer被封裝在CWnd類中,調(diào)用就不用指定窗口句柄了

            于是SetTimer函數(shù)的原型變?yōu)椋?

            UINT SetTimer(UINT nIDEvent,UINT nElapse,void(CALLBACK EXPORT *lpfnTimer)(HWND,UINT ,YINT ,DWORD))

            當(dāng)使用SetTimer函數(shù)的時候,就會生成一個計(jì)時器。函數(shù)中nIDEvent指的是計(jì)時器的標(biāo)識,也就是名字。nElapse指的是時間間隔,
            也就是每隔多長時間觸發(fā)一次事件。第三個參數(shù)是一個回調(diào)函數(shù),在這個函數(shù)里,放入你想要做的事情的代碼,你可以將它設(shè)定為NULL,
            也就是使用系統(tǒng)默認(rèn)的回調(diào)函數(shù),系統(tǒng)默認(rèn)認(rèn)的是onTime函數(shù)。這個函數(shù)怎么生成的呢?你需要在需要計(jì)時器的類的生成onTime函數(shù):
            在ClassWizard里,選擇需要計(jì)時器的類,添加WM_TIME消息映射,就自動生成onTime函數(shù)了。然后在函數(shù)里添加代碼,讓代碼實(shí)現(xiàn)功能。
            每隔一段時間就會自動執(zhí)行一次。

            例:

            SetTimer(1,1000,NULL);

            1:計(jì)時器的名稱;

            1000:時間間隔,單位是毫秒;

            NULL:使用onTime函數(shù)。

            當(dāng)不需要計(jì)時器的時候調(diào)用KillTimer(nIDEvent);

            例如:KillTimer(1);

            2) 調(diào)用回調(diào)函數(shù)

            此方法首先寫一個如下格式的回調(diào)函數(shù)

            void CALLBACK TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime);
            然后再用SetTimer(1,100,TimerProc)函數(shù)來建一個定時器,第三個參數(shù)就是回調(diào)函數(shù)地址。

            二. 或許你會問,如果我要加入兩個或者兩個以上的 timer怎么辦?

            繼續(xù)用SetTimer函數(shù)吧,上次的timer的ID是1,這次可以是2,3,4。。。。

            SetTimer(2,1000,NULL);

            SetTimer(3,500,NULL);

            嗯,WINDOWS會協(xié)調(diào)他們的。當(dāng)然onTimer函數(shù)體也要發(fā)生變化,要在函數(shù)體內(nèi)添加每一個timer的處理代碼:

            onTimer(nIDEvent)

            {
            switch(nIDEvent)

            {
            case 1:........;
            break;
            case 2:.......;
            break;
            case 3:......;
            break;
            }
            }
            本貼來自ZDNetChina中文社區(qū) http://bbs.zdnet.com.cn ,本貼地址:http://bbs.zdnet.com.cn/viewthread.php?tid=313294


            VC定時器 SetTimer 怎么用阿
            Timer事件,即定時器事件,是在游戲編程中,經(jīng)常使用的一個事件。借助它可以產(chǎn)生定時執(zhí)行動作的效果。這篇文章,就和大家一起探討一下如何使用SetTimer()函數(shù)。
            1、SetTimer定義在那里?

            SetTimer表示的是定義個定時器。根據(jù)定義指定的窗口,在指定的窗口(CWnd)中實(shí)現(xiàn)OnTimer事件,這樣,就可以相應(yīng)事件了。

            SetTimer有兩個函數(shù)。一個是全局的函數(shù)::SetTimer()

            UINT SetTimer(
            HWND hWnd, // handle of window for timer messages
            UINT nIDEvent, // timer identifier
            UINT uElapse, // time-out value
            TIMERPROC lpTimerFunc // address of timer procedure
            );

            其中hWnd 是指向CWnd的指針,即處理Timer事件的窗口類。說道窗口類(CWnd),我們有必要來看一下CWnd的繼承情況:CWnd有以下子類:CFrameWnd,CDialog,CView,CControlBar等類。這也意味這些類中都可以定義SetTimer事件。

            同時,SetTimer()在CWnd中也有定義,即SetTimer()是CWnd的一個成員函數(shù)。CWnd的子類可以調(diào)用該函數(shù),來設(shè)置觸發(fā)器。

            UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );

            參數(shù)含義:

            nIDEvent:是指設(shè)置這個定時器的iD,即身份標(biāo)志,這樣在OnTimer()事件中,才能根據(jù)不同的定時器,來做不同的事件響應(yīng)。這個ID是一個無符號的整型。

            nElapse

            是指時間延遲。單位是毫秒。這意味著,每隔nElapse毫秒系統(tǒng)調(diào)用一次Ontimer()。

            void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD)

            Specifies the address of the application-supplied TimerProc callback function that processes the WM_TIMER messages. If this parameter is NULL, the WM_TIMER messages are placed in the application’s message queue and handled by the CWnd object。

            意思是,指定應(yīng)用程序提供的TimerProc回調(diào)函數(shù)的地址,來處里這個Timer事件。如果是NULL,處理這個Timer事件的定義這個Timer的CWnd對象。他將WM_TIMER消息傳遞給這個對象,通過實(shí)現(xiàn)這個對象的OnTimer()事件來處理這個Timer事件。

            所以,一般情況下,我們將這個值設(shè)為NULL,有設(shè)置該定時器的對象中的OnTimer()函數(shù)來處理這個事件。

            同樣的,我們再看看KillTimer()和OnTimer()的定義:

            KillTimer同SetTimer()一樣,他也有兩個,一個是全局的::KillTimer(),另一個是CWnd的一個函數(shù)。他的聲明如下:


            //全局函數(shù)

            BOOL KillTimer(
            HWND hWnd, // handle of window that installed timer
            UINT uIDEvent // timer identifier
            );

            //CWnd函數(shù)

            BOOL KillTimer( int nIDEvent );

            這兩個函數(shù)表示的意思是將iD為nIDEVENT的定時器移走。使其不再作用。其用法如同SetTimer()一樣。

            再看看OnTimer()

            CWnd::OnTimer
            afx_msg void OnTimer( UINT nIDEvent );

            ontimer()是響應(yīng)CWnd對象產(chǎn)生的WM_Timer消息。nIDEvent表示要響應(yīng)TIMER事件的ID。

            二、Timer事件的使用:

            由以上的分析,我們應(yīng)該很清楚,如何來使用Timer事件。假定我們在視圖上畫一個漸變的動畫。我們首先在菜單欄上添加一個菜單項(xiàng),給這個菜單添加命令響應(yīng):

            pView->SetTimer(1,1000,NULL);//pView是視圖類的指針,這里是在視圖類當(dāng)中設(shè)置一個定時器。

            添加完畢,再給視圖類添加一個WM_Timer事件的相應(yīng)。在OnTimer()函數(shù)中編寫漢書,進(jìn)行相應(yīng)。

            如此,就能做出動畫。
            本貼來自ZDNetChina中文社區(qū) http://bbs.zdnet.com.cn ,本貼地址:http://bbs.zdnet.com.cn/viewthread.php?tid=313294

             

             

             

            posted @ 2008-10-25 09:02 wrh 閱讀(4070) | 評論 (0)編輯 收藏

            用GetModuleFileName獲取程序當(dāng)前執(zhí)行文件名

            在開發(fā)過程中經(jīng)常需要獲得程序當(dāng)前的運(yùn)行目錄,這時就可以使用GetModuleFileName函數(shù)
            DWORD WINAPI GetModuleFileName(
              HMODULE hModule,
              LPTSTR lpFileName,
              DWORD nSize
            );

            hModule:要獲取文件名的模塊名柄,null表示當(dāng)前模塊
            lpFileName:輸出參數(shù),存放取得的文件名
            nSize:lpFileName參數(shù)的長度


            void FileName()
            {
                TCHAR lpFileName[MAX_PATH];
                ::GetModuleFileName(null, lpFileName, MAX_PATH);
                SetDlgItemText(IDC_TEXTBOX, lpFileName);
            }


            //==============================================================================

            //==============================================================================
            在開發(fā)軟件的過程里,經(jīng)常需要把數(shù)據(jù)保存到當(dāng)前執(zhí)行文件路徑下面,或者讀取當(dāng)前執(zhí)行文件路徑下的一些配置信息。這時就需要從當(dāng)前模塊里獲取所在的目錄路徑,以便進(jìn)行固定的位置操作文件。要解決這個需求,就需要調(diào)用API函數(shù)GetModuleFileName來獲取模塊所在的路徑。
             
            函數(shù)GetModuleFileName聲明如下:
            WINBASEAPI
            DWORD
            WINAPI
            GetModuleFileNameA(
                __in_opt HMODULE hModule,
                __out_ecount_part(nSize, return + 1) LPCH lpFilename,
                __in     DWORD nSize
                );
            WINBASEAPI
            DWORD
            WINAPI
            GetModuleFileNameW(
                __in_opt HMODULE hModule,
                __out_ecount_part(nSize, return + 1) LPWCH lpFilename,
                __in     DWORD nSize
                );
            #ifdef UNICODE
            #define GetModuleFileName GetModuleFileNameW
            #else
            #define GetModuleFileName GetModuleFileNameA
            #endif // !UNICODE
            hModule是模塊的句柄,或者設(shè)置為NULL表示當(dāng)前模塊。
            lpFilename是保存路徑的緩沖區(qū)。
            nSize是緩沖區(qū)的大小。
             
            調(diào)用函數(shù)的例子如下:
            #001 //獲取當(dāng)前程序所在路徑。
            #002  //蔡軍生 2007/12/05 QQ:9073204 深圳
            #003  void TestGetExePath(void)
            #004  {
            #005         //
            #006         const int nBufSize = 512;
            #007         TCHAR chBuf[nBufSize];
            #008         ZeroMemory(chBuf,nBufSize);
            #009 
            #010         //獲取當(dāng)前執(zhí)行文件的路徑。
            #011        if (GetModuleFileName(NULL,chBuf,nBufSize))
            #012         {
            #013               //輸出帶文件名稱路徑。
            #014               OutputDebugString(chBuf);
            #015               OutputDebugString(_T("\r\n"));
            #016 
            #017               //獲取文件路徑。
            #018               TCHAR* lpStrPath = chBuf;
            #019               PathRemoveFileSpec(lpStrPath);
            #020               OutputDebugString(lpStrPath);
            #021               OutputDebugString(_T("\r\n"));
            #022         }
            #023 
            #024  }
             
            輸出的結(jié)果如下:
            g:\work\windows_api\wincpp2\debug\WinCpp.exe
            g:\work\windows_api\wincpp2\debug
            posted @ 2008-10-21 09:45 wrh 閱讀(4803) | 評論 (0)編輯 收藏
            僅列出標(biāo)題
            共25頁: First 15 16 17 18 19 20 21 22 23 Last 

            導(dǎo)航

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統(tǒng)計(jì)

            常用鏈接

            留言簿(19)

            隨筆檔案

            文章檔案

            收藏夾

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            国产精品久久精品| 99久久婷婷国产综合亚洲| 中文成人久久久久影院免费观看 | 国产999精品久久久久久| 99久久99久久精品国产片果冻| 国产精品美女久久久网AV| 久久久久亚洲AV成人网人人软件| 久久综合久久鬼色| 亚洲日韩中文无码久久| 狠狠干狠狠久久| 免费精品国产日韩热久久| 国产情侣久久久久aⅴ免费| 国产精品欧美亚洲韩国日本久久| 2021最新久久久视精品爱| 国产精品一久久香蕉国产线看观看| 成人精品一区二区久久久| 偷偷做久久久久网站| 色综合久久综合网观看| 久久精品免费全国观看国产| 国产精品久久久久天天影视| 伊人久久大香线蕉无码麻豆| 久久99精品久久久久久| 无码任你躁久久久久久久| 91精品国产高清久久久久久io| 久久久久亚洲爆乳少妇无| 久久久精品人妻一区二区三区蜜桃| 精品水蜜桃久久久久久久| 狼狼综合久久久久综合网| 久久毛片免费看一区二区三区| 国产精品久久久福利| 日本WV一本一道久久香蕉| 国产成人AV综合久久| 91视频国产91久久久| 丁香色欲久久久久久综合网| 久久精品国产精品青草app| 久久久久亚洲AV无码专区首JN | 久久福利青草精品资源站免费| 久久人妻无码中文字幕| 欧美久久久久久午夜精品| 亚洲国产成人久久精品影视| 99久久99久久久精品齐齐|