• <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>

            斜樹的空間

            集中精力,放棄一切的去做一件事情,只要盡力了,即使失敗了,你也不會后悔!

              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
              47 隨筆 :: 0 文章 :: 12 評論 :: 0 Trackbacks

            #


            一:列文件清單
            1. List
            (gdb) list line1,line2

            二:執行程序
            要想運行準備 調試的程序,可使用run命令,在它后面可以跟隨發給該程序的任何參數,包括標準輸入和標準輸出說明符(<和>)和外殼通配符 (*、?、[、])在內。
            如果你使用不帶參數的run命令,gdb就再次使用你給予前一條run命令的參數,這是很有用的。
            利用 set args 命令就可以修改發送給程序的參數,而使用show args 命令就可以查看其缺省參數的列表。
            (gdb)set args –b –x
            (gdb) show args
            backtrace命令為堆棧提供向后跟蹤功能。
            Backtrace 命令產生一張列表,包含著從最近的過程開始的所以有效過程和調用這些過程的參數。

            三:顯示數據
            利用print 命令可以檢查各個變量的值。
            (gdb) print p (p為變量名)
            whatis 命令可以顯示某個變量的類型
            (gdb) whatis p
            type = int *

            print 是gdb的一個功能很強的命令,利用它可以顯示被調試的語言中任何有效的表達式。表達式除了包含你程序中的變量外,還可以包含以下內容:
            l 對程序中函數的調用
            (gdb) print find_entry(1,0)
            l 數據結構和其他復雜對象
            (gdb) print *table_start
            $8={e=reference=’\000’,location=0x0,next=0x0}
            l 值的歷史成分
            (gdb)print $1 ($1為歷史記錄變量,在以后可以直接引用 $1 的值)
            l 人為數組
            人為數 組提供了一種去顯示存儲器塊(數組節或動態分配的存儲區)內容的方法。早期的調試程序沒有很好的方法將任意的指針換成一個數組。就像對待參數一樣,讓我們 查看內存中在變量h后面的10個整數,一個動態數組的語法如下所示:
            base@length
            因此,要想顯示在h后面的10個元素,可 以使用h@10:
            (gdb)print h@10
            $13=(-1,345,23,-234,0,0,0,98,345,10)

            四: 斷點(breakpoint)
            break命令(可以簡寫為b)可以用來在調試的程序中設置斷點,該命令有如下四種形式:
            l break line-number 使程序恰好在執行給定行之前停止。
            l break function-name 使程序恰好在進入指定的函數之前停止。
            l break line-or-function if condition 如果condition(條件)是真,程序到達指定行或函數時停止。
            l break routine-name 在指定例程的入口處設置斷點

            如 果該程序是由很多原文件構成的,你可以在各個原文件中設置斷點,而不是在當前的原文件中設置斷點,其方法如下:
            (gdb) break filename:line-number
            (gdb) break filename:function-name

            要想設置 一個條件斷點,可以利用break if命令,如下所示:
            (gdb) break line-or-function if expr
            例:
            (gdb) break 46 if testsize==100

            從斷點繼續運行:countinue 命令
            五. 斷點的管理

            1. 顯示當前gdb的斷點信息:
            (gdb) info break
            他會以如下的形式顯示所有的斷點信 息:
            Num Type Disp Enb Address What
            1 breakpoint keep y 0x000028bc in init_random at qsort2.c:155
            2 breakpoint keep y 0x0000291c in init_organ at qsort2.c:168
            (gdb)
            2.刪除指定的某個斷點:
            (gdb) delete breakpoint 1
            該命令將會刪除編號為1的斷點,如果不帶編號參數,將刪除所有的斷點
            (gdb) delete breakpoint
            3.禁止使用某個斷點
            (gdb) disable breakpoint 1
            該命令將禁止斷點 1,同時斷點信息的 (Enb)域將變為 n
            4.允許使用某個斷點
            (gdb) enable breakpoint 1
            該 命令將允許斷點 1,同時斷點信息的 (Enb)域將變為 y
            5.清除原文件中某一代碼行上的所有斷點
            (gdb)clean number
            注:number 為原文件的某個代碼行的行號
            六.變量的檢查和賦值
            l whatis:識別數組或變量的類型
            l ptype:比whatis的功能更強,他可以提供一個結構的定義
            l set variable:將值賦予變量
            l print 除了顯示一個變量的值外,還可以用來賦值

            七.單步執行
            l next
            不進入的單步執行
            l step
            進入的單步執行
            如果已經進入了某函數,而想退出該函數返回到它的調用函數中,可使用命令finish
            八.函數的調 用
            l call name 調用和執行一個函數
            (gdb) call gen_and_sork( 1234,1,0 )
            (gdb) call printf(“abcd”)
            $1=4
            l finish 結束執行當前函數,顯示其返回值(如果有的話)

            九. 機器語言工具
            有一組專用的gdb變量可以用來檢查和修改計算機的通用寄存器,gdb提供了目前每一臺計算機中實際使用的4個寄存器的標準名字:
            l $pc : 程序計數器
            l $fp : 幀指針(當前堆棧幀)
            l $sp : 棧指針
            l $ps : 處理器狀態

            十.信號
            gdb通常可以捕捉到發送給它的大多數信號,通過捕捉信號,它就可決定對于正在運行的進程要做些什么工 作。例如,按CTRL-C將中斷信號發送給gdb,通常就會終止gdb。但是你或許不想中斷gdb,真正的目的是要中斷gdb正在運行的程序,因 此,gdb要抓住該信號并停止它正在運行的程序,這樣就可以執行某些調試操作。

            Handle命令可控制信號的處理,他有兩個參數,一個 是信號名,另一個是接受到信號時該作什么。幾種可能的參數是:
            l nostop 接收到信號時,不要將它發送給程序,也不要停止程序。
            l stop 接受到信號時停止程序的執行,從而允許程序調試;顯示一條表示已接受到信號的消息(禁止使用消息除外)
            l print 接受到信號時顯示一條消息
            l noprint 接受到信號時不要顯示消息(而且隱含著不停止程序運行)
            l pass 將信號發送給程序,從而允許你的程序去處理它、停止運行或采取別的動作。
            l nopass 停止程序運行,但不要將信號發送給程序。
            例 如,假定你截獲SIGPIPE信號,以防止正在調試的程序接受到該信號,而且只要該信號一到達,就要求該程序停止,并通知你。要完成這一任務,可利用如下 命令:
            (gdb) handle SIGPIPE stop print
            請注意,UNIX的信號名總是采用大寫字母!你可以用信號編 號替代信號名
            如果你的程序要執行任何信號處理操作,就需要能夠測試其信號處理程序,為此,就需要一種能將信號發送給程序的簡便方法,這就是 signal命令的任務。該 命令的參數是一個數字或者一個名字,如SIGINT。假定你的程序已將一個專用的SIGINT(鍵盤輸入,或CTRL-C;信號2)信號處理程序設置成采 取某個清理動作,要想測試該信號處理程序,你可以設置一個斷點并使用如下命令:
            (gdb) signal 2
            continuing with signal SIGINT(2)
            該程序繼續執行,但是立即傳輸該信號,而且處理程序開始運行.

            十一. 原文件的搜索
            search text:該命令可顯示在當前文件中包含text串的下一行。
            Reverse-search text:該命令可以顯示包含text 的前一行。

            十二.UNIX接口
            shell 命令可啟動UNIX外殼,CTRL-D退出外殼,返回到 gdb.

            十三.命令的歷史
            為了允許使用歷史命令,可使用 set history expansion on 命令
            (gdb) set history expansion on

            小結:常用 的gdb命令
            backtrace 顯示程序中的當前位置和表示如何到達當前位置的棧跟蹤(同義詞:where)
            breakpoint 在程序中設置一個斷點
            cd 改變當前工作目錄
            clear 刪除剛才停止處的斷點
            commands 命中斷點時,列出將要執行的命令
            continue 從斷點開始繼續執行
            delete 刪除一個斷點或監測點;也可與其他命令一起使用
            display 程序停止時顯示變量和表達時
            down 下移棧幀,使得另一個函數成為當前函數
            frame 選擇下一條continue命令的幀
            info 顯示與該程序有關的各種信息
            jump 在源程序中的另一點開始運行
            kill 異常終止在gdb 控制下運行的程序
            list 列出相應于正在執行的程序的原文件內容
            next 執行下一個源程序行,從而執行其整體中的一個函數
            print 顯示變量或表達式的值
            pwd 顯示當前工作目錄
            pype 顯示一個數據結構(如一個結構或C++類)的內容
            quit 退出gdb
            reverse-search 在源文件中反向搜索正規表達式
            run 執行該程序
            search 在源文件中搜索正規表達式
            set variable 給變量賦值
            signal 將一個信號發送到正在運行的進程
            step 執行下一個源程序行,必要時進入下一個函數
            undisplay display命令的反命令,不要顯示表達式
            until 結束當前循環
            up 上移棧幀,使另一函數成為當前函數
            watch 在程序中設置一個監測點(即數據斷點)
            whatis 顯示變量或函數類型
            ****************************************************
             GNU的調試器稱為gdb,該程序是一個交互式工具,工作在字符模式。在 X Window 系統中,有一個gdb的前端圖形工具,稱為xxgdb。gdb 是功能強大的調試程序,可完成如下的調試任務:
              * 設置斷點;
            * 監視程序變量的值;
              * 程序的單步執行;
              * 修改變量的值。
              在可以使用 gdb 調試程序之前,必須使用 -g 選項編譯源文件。可在 makefile 中如下定義 CFLAGS 變量:
               CFLAGS = -g
            運行 gdb 調試程序時通常使用如下的命令:
               gdb progname

              在 gdb 提示符處鍵入help,將列出命令的分類,主要的分類有:
              * aliases:命令別名
              * breakpoints:斷點定義;
              * data:數據查看;
              * files:指定并查看文件;
              * internals:維護命令;
              * running:程序執行;
              * stack:調用棧查看;
              * statu:狀態查看;
              * tracepoints:跟蹤程序執行。
              鍵入 help 后跟命令的分類名,可獲得該類命令的詳細清單。


            gdb 的常用命令
            命令 解釋
              break NUM 在指定的行上設置斷點。
              bt 顯示所有的調用棧幀。該命令可用來顯示函數的調用順序。
              clear 刪除設置在特定源文件、特定行上的斷點。其用法為clear FILENAME:NUM
              continue 繼續執行正在調試的程序。該命令用在程序由于處理信號或斷點而 導致停止運行時。
              display EXPR 每次程序停止后顯示表達式的值。表達式由程序定義的變量組成。
              file FILE 裝載指定的可執行文件進行調試。
              help NAME 顯示指定命令的幫助信息。
              info break 顯示當前斷點清單,包括到達斷點處的次數等。
              info files 顯示被調試文件的詳細信息。
              info func 顯示所有的函數名稱。
              info local 顯示當函數中的局部變量信息。
              info prog 顯示被調試程序的執行狀態。
              info var 顯示所有的全局和靜態變量名稱。
              kill 終止正被調試的程序。
              list 顯示源代碼段。
              make 在不退出 gdb 的情況下運行 make 工具。
              next 在不單步執行進入其他函數的情況下,向前執行一行源代碼。
              print EXPR 顯示表達式 EXPR 的值。

            ******gdb 使用范例************************
            -----------------
            清單 一個有錯誤的 C 源程序 bugging.c
            代碼:

            -----------------
            1 #i nclude
            2
            3 static char buff [256];
            4 static char* string;
            5 int main ()
            6 {
            7   printf ("Please input a string: ");
            8 gets (string);  
            9   printf ("\nYour string is: %s\n", string);
            10 }


            -----------------
            上面這個程序非常簡單,其目的是接受用戶的輸入,然后將用戶的輸入打印出來。該程序使用了一個未經過初始化的字符串地址 string,因此,編譯并運行之后,將出現 Segment Fault 錯誤:
            $ gcc -o bugging -g bugging.c
            $ ./bugging
            Please input a string: asfd
            Segmentation fault (core dumped)
            為了查找該程序中出現的問題,我們利用 gdb,并按如下的步驟進行:
            1.運行 gdb bugging 命令,裝入 bugging 可執行文件;
            2.執行裝入的 bugging 命令 run;
            3.使用 where 命令查看程序出錯的地方;
            4.利用 list 命令查看調用 gets 函數附近的代碼;
            5.唯一能夠導致 gets 函數出錯的因素就是變量 string。用print命令查看 string 的值;
            6.在 gdb 中,我們可以直接修改變量的值,只要將 string 取一個合法的指針值就可以了,為此,我們在第8行處設置斷點 break 8;
            7.程序重新運行到第 8行處停止,這時,我們可以用 set variable 命令修改 string 的取值;
            8.然后繼續運行,將看到正確的程序運行結果。
            (http://www.fanqiang.com)

            posted @ 2010-10-12 11:56 張貴川 閱讀(687) | 評論 (0)編輯 收藏


            Unix已經有35年歷史了。許多人認為它開始于中世紀,這個中世紀是相對于
            計算機技術的產生和發展來說的。在過去的時間里,Unix和它的子分支Linux收集
            有許多的歷史和一些完全古老的語言。在這篇技巧文章中,我們將介紹一少部分古
            老的語言和它們的目的和作用,以及它們真正的來源。 

            RC 

            在Linux中,最為常用的縮略語也許是“rc”,它是“runcomm”的縮寫――即名詞
            “run   command”(運行命令)的簡寫。今天,“rc”是任何腳本類文件的后綴,這些
            腳本通常在程序的啟動階段被調用,通常是Linux系統啟動時。如   
            /etc/rs是
            Linux啟動的主腳本,而.bashrc是當Linux的bash   shell啟動后所運行的腳
            本。.bashrc的前綴“.”是一個命名標準,它被設計用來在用戶文件中隱藏那些用戶
            指定的特殊文件;“ls”命令默認情況下不會列出此類文件,“rm”默認情況下也不會
            刪除它們。許多程序在啟動時,都需要“rc”后綴的初始文件或配置文件,這對于
            Unix的文件系統視圖來說,沒有什么神秘的。 

            ETC 

            在“etc
            /bin”中的“etc”真正代表的是“etcetera”(附加物)。在早期的Unix系
            統中,最為重要的目錄是“bin”目錄   (“bin”是“binaries”二進制文件――編譯后的
            程序的縮寫),“etc”中則包含瑣碎的程序,如啟動、關機和管理。運行一個Linux
            必須的東西的列表是:一個二進制程序,etcetera,etcetera――換句話說,是一個
            底層的重要項目,通常添加一些次等重要的零碎事物。今天,   “etc”包含了廣泛
            的系統配置文件,這些配置文件幾乎包含了系統配置的方方面面,同樣非常重要。 

            Bin 

            今天,許多在Linux上運行的大型子系統,如GNOME或Oracle,所編譯成的程
            序使用它們自己的“bin”目錄(或者是   
            /usr/bin,或者是/usr/local/bin)作為標
            準的存放地。同樣,現在也能夠在這些目錄看到腳本文件,因為“bin”目錄通常添
            加到用戶的PATH路徑中,這樣他們才能夠正常的使用程序。因此運行腳本通常在
            bin中運行良好。 

            TTY 

            在Linux中,TTY也許是跟終端有關系的最為混亂的術語。TTY是TeleTYpe的
            一個老縮寫。Teletypes,或者   teletypewriters,原來指的是電傳打字機,是
            通過串行線用打印機鍵盤通過閱讀和發送信息的東西,和古老的電報機區別并不是
            很大。之后,當計算機只能以批處理方式運行時(當時穿孔卡片閱讀器是唯一一種
            使程序載入運行的方式),電傳打字機成為唯一能夠被使用的“實時”輸入
            /輸出設
            備。最終,電傳打字機被鍵盤和顯示器終端所取代,但在終端或   TTY接插的地
            方,操作系統仍然需要一個程序來監視串行端口。一個getty“Get   TTY”的處理過
            程是:一個程序監視物理的TTY
            /終端接口。對一個虛擬網絡沮喪服務器(VNC)來說,
            一個偽裝的TTY(Pseudo
            -TTY,即家貓的TTY,也叫做“PTY”)是等價的終端。當你運
            行一個xterm(終端仿真程序)或GNOME終端程序時,PTY對虛擬的用戶或者如xterm一
            樣的偽終端來說,就像是一個TTY在運行。“Pseudo”的意思是“duplicating   
            in 
            a   fake   way”(用偽造的方法復制),它相比“
            virtual”或“emulated”更能真實的
            說明問題。而在現在的計算中,它卻處于被放棄的階段。 

            Dev 

            從TTY留下的命令有“stty”,是“
            set   tty”(設置TTY)的縮寫,它能夠生成
            一個配置文件
            /etc/initab(“initialization   table”,初始表),以配置gettys
            使用哪一個串口。在現代,直接附加在Linux窗口上的唯一終端通常是控制臺,由
            于它是特殊的TTY,因此被命名為“console”。當然,一旦你啟動
            X11,“console”TTY就會消失,再也不能使用串口協議。所有的TTY都被儲存在
            /dev”目錄,它是“[physical]   devices”([物理]設備)的縮寫。以前,你必須在
            電腦后面的串口中接入一個新的終端時,手工修改和配置每一個設備文件。現
            在,Linux(和   Unix)在安裝過程中就在此目錄中創建了它所能向導的每一個設備
            的文件。這就是說,你很少需要自己創建它。 

            隨著硬件在電腦中的移出移進,這些名字將變得更加模糊不清。幸運的是,
            今天在Linux上的高等級軟件塊對歷史和硬件使用容易理解的名字。舉例來說,
            嗯,Pango(http:
            //www.pango.org/)就是其中之一。 

            如果你對這些內容很感興趣,那么我建議你閱讀宏大的,但有些以美國英語
            歷史為中心的,由Eric   S.   Raymond撰寫的Jargon   File。它并沒有解釋所有
            在Unix中使用的術語,但是它給出了這些形成的大致情況。  

            posted @ 2010-10-11 23:29 張貴川 閱讀(270) | 評論 (0)編輯 收藏

            獲得CWinApp:
             -在CMainFrame,CChildFrame,CDocument,CView中直接調用AfxGetApp()或用theApp
             -在其它類中只能用AfxGetApp()

            獲得CMainFrame:
             -在CMinApp中用AfxGetMainWnd()或者m_pMainWnd
             -在CChildFrame中可用GetParentFrame()
             -在其它類中用AfxGetMainWnd()

            獲得CChildFrame:
             -在CView中用GetParentFrame()
             -在CMainFrame中用MDIGetActive()或GetActiveFrame()
             -在其它類中用AfxGetMainWnd()->MDIGetActive()或AfxGetMainWnd()->GetActiveFrame()

            獲得CDocument:
             -在CView中用GetDocument()
             -在CChildFrame中用GetActiveView()->GetDocument()
             -在CMainFrame中用
              -if SDI:GetActiveView()->GetDocument()
              -if MDI:MDIGetActive()->GetActiveView()->GetDocument()
             -在其它類中
              -if SDI:AfxGetMainWnd()->GetActiveView()->GetDocument()
              -if MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument()

            獲得CView:
             -在CDocument中 POSITION pos = GetFirstViewPosition();GetNextView(pos)
             -在CChildFrame中 GetActiveView()
             -在CMainFrame中
              -if SDI:GetActiveView()
              -if MDI:MDIGetActive()->GetActiveView()
             -在其它類中
              -if SDI:AfxGetMainWnd()->GetActiveView()
              -if MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()


            不過要注意在doc中要取得view的指針C*View要注意類C*View聲明的問題,
            因為默認情況下,mfc在*View.h中已經包含了*Doc.h,如果在*Doc.h中包含
            *View.h,就會引起嵌套包含問題,這樣要在*Doc.h中加入 class C*View;
            而在*Doc.cpp中加入 #include "*View.h"

            //////////////////////////////////////////////////////////////////
            其實完全可以在CYourApp中添加各種視或文檔的指針,在那些視或文檔初
            始化的時候將指針傳給CYourApp中的對應變量,這樣以后不管在哪用上面
            指針只需(CYourApp*)AfxGetApp()取其屬性變量即可,明了而且清楚更是
            方便我一直專門操作的說:)

            //////////////////////////////////////////////////////////////////
            我先拋塊磚,有玉的砸過來!
            在何時何地,你都可以通過以下方法精確的得到任何一個對象(Application,DocTemplate,Document,View,Frame)
            1。通過AfxGetApp()得到當前的App對象;
            2。通過AfxGetMainWnd()得到主窗口;
            3。通過CMDIFrameWnd::GetActiveFrame得到當前活動窗口;
            4。通過GetNextWindow()遍例所有的子窗口;(如果要得到你想要的子窗口,可以通過特定的成員變量來標志);
            5。通過CWinApp::GetFirstDocTemplatePostion()以及CWinApp::GetNextDocTemplate()的組合應用來遍歷所有的DocTemplate對象,并且用CDocTemplate::GetDocString()來判斷當前得到的文檔莫板對象是哪個。
            6。通過CDocTemplate::GetFirstDocPosition()以及CDocTemplate的GetNextDoc()組合來遍歷所有的該模板的文檔對象,并用CDocument::GetDocTemplate()來得到文檔模板,用CDocment::GetTitle() 或者GetPathName()來判斷當前的文檔是哪個。
            7。通過CDocuemt的GetFirstViewPositon()以及GetNextView()來遍歷視圖對象,一般通過訪問View的成員變量來區別各個視圖;通過CView::GetDocument()來得到文檔對象;
            8。Frame->View: 通過GetActiveView方法;
            9。Frame->Doc:通過GetActiveDocument();
            10。View->Frame:GetParentFrame();
            11。View->Doc:GetDocuemt()//前面已經說了。
            12。Doc->View:前面說了;
            13。Doc->Frame:不知道有沒有很直接的方法。
            MFC應用程序中指針的使用

            1) 在View中獲得Doc指針
            2) 在App中獲得MainFrame指針
            3) 在View中獲得MainFrame指針
            4) 獲得View(已建立)指針
            5) 獲得當前文檔指針
            6) 獲得狀態欄與工具欄指針
            7) 獲得狀態欄與工具欄變量
            8) 在Mainframe獲得菜單指針
            9) 在任何類中獲得應用程序類
            10) 從文檔類取得視圖類的指針(1)
            11) 在App中獲得文檔模板指針
            12) 從文檔模板獲得文檔類指針
            13) 在文檔類中獲得文檔模板指針
            14) 從文檔類取得視圖類的指針(2)
            15) 從一個視圖類取得另一視圖類的指針

            VC中編程對于剛剛開始學習的同學,最大的障礙和問題就是消息機制和指針獲取與
            操作。其實這些內容基本上是每本VC學習工具書上必講的內容,而且通過MSDN很多
            問題都能解決。下面文字主要是個人在編程中指針使用的一些體會,說的不當的地
            方請指正。一般我們使用的框架是VC提供的Wizard生成的MFC App Wizard(exe)框架,
            無論是多文檔還是單文檔,都存在指針獲取和操作問題。下面這節內容主要是一般
            的框架,然后再講多線程中的指針使用。使用到的類需要包含響應的頭文件。首先
            一般獲得本類(視,文檔,對話框都支持)實例指針this,用this的目的,主要可以通
            過類中的函數向其他類或者函數中發指針,以便于在非本類中操作和使用本類中的
            功能。

             1) 在View中獲得Doc指針 CYouSDIDoc *pDoc=GetDocument();一個視只能有一個文
            檔。
             2) 在App中獲得MainFrame指針
            CWinApp 中的 m_pMainWnd變量就是MainFrame的指針
            也可以: CMainFrame *pMain =(CMainFrame *)AfxGetMainWnd();
             3) 在View中獲得MainFrame指針 CMainFrame *pMain=(CmaimFrame *)AfxGetApp()->m_pMainWnd;
             4) 獲得View(已建立)指針 CMainFrame *pMain=(CmaimFrame *)AfxGetApp()->m_pMainWnd;
            CyouView *pView=(CyouView *)pMain->GetActiveView();
             5) 獲得當前文檔指針 CDocument * pCurrentDoc =(CFrameWnd *)m_pMainWnd->GetActiveDocument();
             6) 獲得狀態欄與工具欄指針 CStatusBar * pStatusBar=(CStatusBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR);
            CToolBar * pToolBar=(CtoolBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_TOOLBAR);

             7) 如果框架中加入工具欄和狀態欄變量還可以這樣
            (CMainFrame *)GetParent()->m_wndToolBar;
            (CMainFrame *)GetParent()->m_wndStatusBar;

             8) 在Mainframe獲得菜單指針 CMenu *pMenu=m_pMainWnd->GetMenu();
             9) 在任何類中獲得應用程序類
            用MFC全局函數AfxGetApp()獲得。

             10) 從文檔類取得視圖類的指針
            我是從http://download.cqcnc.com/soft/program/article/vc/vc405.html學到的,
            從文檔獲得視圖類指針目的一般為了控制同一文檔的多個視圖的定位問題,我的體會
            特別是文字處理CEditView當產生多個視圖類時,這個功能是非常需要的。
            CDocument類提供了兩個函數用于視圖類的定位:
            GetFirstViewPosition()和GetNextView()
            virtual POSITION GetFirstViewPosition() const;
            virtual CView* GetNextView(POSITION& rPosition) const;

            注意:GetNextView()括號中的參數用的是引用方式,因此執行后值可能改變。
            GetFirstViewPosition()用于返回第一個視圖位置(返回的并非視圖類指針,而是一
            個POSITION類型值),GetNextView()有兩個功能:返回下一個視圖類的指針以及用
            引用調用的方式來改變傳入的POSITION類型參數的值。很明顯,在Test程序中,只有
            一個視圖類,因此只需將這兩個函數調用一次即可得到CTestView的指針如下(需定
            義一個POSITION結構變量來輔助操作):
            CTestView* pTestView;
            POSITION pos=GetFirstViewPosition();
            pTestView=GetNextView(pos);

            這樣,便可到了CTestView類的指針pTestView.執行完幾句后,變量pos=NULL,因為沒
            有下一個視圖類,自然也沒有下一個視圖類的POSITION.但是這幾條語句太簡單,不
            具有太強的通用性和安全特征;當象前面說的那樣,當要在多個視圖為中返回某個指
            定類的指針時,我們需要遍歷所有視圖類,直到找到指定類為止。判斷一個類指針指
            向的是否某個類的實例時,可用IsKindOf()成員函數時行檢查,如:
             pView->IsKindOf(RUNTIME_CLASS(CTestView));
            即可檢查pView所指是否是CTestView類。

            有了以上基礎,我們已經可以從文檔類取得任何類的指針。為了方便,我們將其作
            為一個文檔類的成員函數,它有一個參數,表示要獲得哪個類的指針。實現如下:
            CView* CTestDoc::GetView(CRuntimeClass* pClass)
            {
             CView* pView;
             POSITION pos=GetFirstViewPosition();

             while(pos!=NULL){
              pView=GetNextView(pos);
              if(!pView->IsKindOf(pClass))
              break;
             }

             if(!pView->IsKindOf(pClass)){
              AfxMessageBox("Connt Locate the View.\r\n http://www.VCKBASE.com");
              return NULL;
             }

             return pView;
            }

            其中用了兩次視圖類的成員函數IsKindOf()來判斷,是因為退出while循環有三種
            可能:

            1.pos為NULL,即已經不存在下一個視圖類供操作;
            2.pView已符合要求。

            1和2同是滿足。這是因為GetNextView()的功能是將當前視圖指針改變成一個視圖
            的位置同時返回當前視圖指針,因此pos是pView的下一個視圖類的POSITION,完全
            有可能既是pos==NULL又是pView符合需要。當所需的視圖是最后一個視圖是最后一
            個視圖類時就如引。因此需采用兩次判斷。
            使用該函數應遵循如下格式(以取得CTestView指針為例):
            CTestView* pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView));
            RUNTIME_CLASS是一個宏,可以簡單地理解它的作用:將類的名字轉化為
            CRuntimeClass為指針。至于強制類型轉換也是為了安全特性考慮的,因為從同一個
            基類之間的指針類型是互相兼容的。這種強制類型轉換也許并不必要,但能避免一
            些可能出現的麻煩。

            3.從一個視圖類取得另一視圖類的指針綜合1和2,很容易得出視圖類之間互相獲得
            指針的方法:就是用文檔類作中轉,先用1的方法得到文檔類的指針,再用2的方法,
            以文檔類的視圖定位函數取得另一個視圖類。同樣,可以實現成一個函數:
            (假設要從CTestAView中取得指向其它視圖類的指針)
            CView* CTestAView::GetView(CRuntimeClass* pClass)
            {
             CTestDoc* pDoc=(CTestDoc*)GetDocument();
             CView* pView;
             POSITION pos=pDoc->GetFirstViewPosition();
             while(pos!=NULL){
              pView=pDoc->GetNextView(pos);
              if(!pView->IsKindOf(pClass))
              break;
             }
             if(!pView->IsKindOf(pClass)){
              AfxMessageBox("Connt Locate the View.");
              return NULL;
             }

             return pView;
            }
            這個函數和2中的GetView()相比,一是多了第一句以取得文檔類指針,二是在
            GetFirstViewPosition()和GetNextView()前加上了文檔類指針,以表示它們是文檔
            類成員函數。有了此函數;當要從CTestAView中取得CTestBView的指針時,只需如
            下:CTestBView* pTestbView=(CTestView*)GetView(RUNTIME_CLASS(CTestBView));
            11)對于單文檔中也可以加入多個文檔模板,但是一般的開發就使用MDI方式開發
            多文檔模板,其方法與上述視圖的獲取方法很接近,這里稍做解釋,如果不清楚,
            請查閱MSDN,(以下四個內容(11、12、13、14)來源:
            http://sanjianxia.myrice.com/vc/vc45.htm

            可以用CWinApp::GetFirstDocTemplatePostion獲得應用程序注冊的第一個文檔模板
            的位置;利用該值來調用CWinApp::GetNextDocTemplate函數,獲得第一個
            CDocTemplate對象指針。 POSITION GetFirstDocTemplate( ) const;
            CDocTemplate *GetNextDocTemplate( POSITION & pos ) const;

            第二個函數返回由pos 標識的文檔模板。POSITION是MFC定義的一個用于迭代或對象
            指針檢索的值。通過這兩個函數,應用程序可以遍歷整個文檔模板列表。如果被檢索
            的文檔模板是模板列表中的最后一個,則pos參數被置為NULL。

             12)一個文檔模板可以有多個文檔,每個文檔模板都保留并維護了一個所有對應文
            檔的指針列表。
            用CDocTemplate::GetFirstDocPosition函數獲得與文檔模板相關的文檔集合中第一
            個文檔的位置,并用POSITION值作為CDocTemplate::GetNextDoc的參數來重復遍歷與
            模板相關的文檔列表。函數原形為:
            viaual POSITION GetFirstDocPosition( ) const = 0;
            visual CDocument *GetNextDoc(POSITION & rPos) const = 0; 

            如果列表為空,則rPos被置為NULL.

             13)在文檔中可以調用CDocument::GetDocTemplate獲得指向該文檔模板的指針。
            函數原形如下: CDocTemplate * GetDocTemplate ( ) const;
            如果該文檔不屬于文檔模板管理,則返回值為NULL。

             14)一個文檔可以有多個視。每一個文檔都保留并維護一個所有相關視的列表。
            CDocument::AddView將一個視連接到文檔上,將該視加入到文檔相聯系的視的列表
            中,并將視的文檔指針指向該文檔。當有File/New、File/Open、Windows/New或
            Window/Split的命令而將一個新創建的視的對象連接到文檔上時, MFC會自動調用
            該函數,框架通過文檔/視的結構將文檔和視聯系起來。當然,程序員也可以根據自
            己的需要調用該函數。
            Virtual POSITION GetFirstViewPosition( ) const;
            Virtual CView * GetNextView( POSITION &rPosition) cosnt;

            應用程序可以調用CDocument::GetFirstViewPosition返回與調用文檔相聯系的視的
            列表中的第一個視的位置,并調用CDocument::GetNextView返回指定位置的視,并將
            rPositon的值置為列表中下一個視的POSITION值。如果找到的視為列表中的最后一個
            視,則將rPosition置為NULL.

             15)從一個視圖類取得另一視圖類的指針
            這個應用在多視的應用程序中很多見,一般如果自己在主程序或者主框架中做好變
            量記號,也可以獲得,還有比較通用的就是用文檔類作中轉,以文檔類的視圖遍歷
            定位,取得另一個視圖類。這個功能從本文第10項中可以得到。


            轉自:http://m.shnenglu.com/justin-shi/archive/2008/06/14/53196.html

            posted @ 2010-08-28 12:33 張貴川 閱讀(267) | 評論 (0)編輯 收藏

            屬性-》C/C++-》預編譯頭-》創建使用預編譯頭-》不使用
             

            posted @ 2010-08-02 22:42 張貴川 閱讀(3162) | 評論 (1)編輯 收藏

               工具欄(ToolBar)是一種非常方便的控件,能大大增加用戶操作的效率,但是基于對話框的程序,卻不能像使用編輯框(Edit Box)和列表框(List Box)一樣,方便地增加工具欄控件。本文將介紹一種在對話框中加入工具欄的方法。

              一、 技術要點分析

              所有的Windows控件(包括工具欄、編輯框等)都派生自CWnd類,這就意味著,我們可以用窗口類的Create()函數把它們“創建”并顯示到另一個窗口(例如對話框)上。把工具欄加入到對話框中正是使用了這樣的一種方法。

              通常,我們使用CToolBarCtrl類(派生自CWnd類)來創建并管理工具欄控件。使用這個類創建一條工具欄的一般步驟如下:

              1.派生一個CToolBarCtrl的對象;

              2.調用CToolBarCtrl::Create函數創建工具欄對象;

              3.調用CToolBarCtrl::AddBitmap()和CToolBarCtrl::AddString()為工具欄對象加入位圖和提示信息;

              4.派生一個TBUTTON數組對象進行工具欄中各按鈕的具體設置;

              5.修改主窗口的OnNotify()函數,以顯示工具欄上的提示信息。

              以上步驟在下面的范例代碼中會有具體體現。


              二、 范例程序的建立與主要代碼分析


              利用Visual C++ 的向導生成一個基于對話框的程序,命名為ToolBarInDial。修改主對話框樣式如圖1。繪出一條工具欄的位圖并建立一選單,設置幾個子選單項,然后建立一組工具欄的提示信息串(String Table),一旦鼠標在工具欄某項上停留,就會顯示提示信息。下面給出程序中的主要代碼。

              在主對話框CToolBarInDialDlg的類定義中有如下的變量說明:

              CToolBarCtrl ToolBar;

              int ButtonCount;

              int ButtonBitmap;

              BOOL DoFlag;

              TBBUTTON m_Button[5];

              //設置工具欄上具體信息的變量數組

              //主對話框的初始化函數

              BOOL CToolBarInDialDlg::OnInitDialog()

              {

              RECT rect;

              //設置工具欄的顯示范圍

              rect.top=0; rect.left=0; rect.right=48; rect.bottom=16;

              ToolBar.Create(WS_CHILD|WS_VISIBLE|CCS_TOP|TBSTYLE_TOOLTIPS|CCS_ADJUSTABLE,rect,this,0);

              //建立工具欄并設置工具欄的樣式

              ButtonBitmap=ToolBar.AddBitmap(5,IDB_PLAY); //加入工具欄的位圖

              ButtonString=ToolBar.AddString(IDS_FIRST);//加入工具欄的提示信息

              //以下代碼開始設置各具體的按鈕

              m_Buttons[ButtonCount].iBitmap=

              ButtonBitmap+ButtonCount; //ButtonCount初值為0

              m_Buttons[ButtonCount].idCommand=ID_PLAY; //工具欄與選單上某子項對應

              m_Buttons[ButtonCount].fsState=TBSTATE_ENABLED;

              //設置工具欄按鈕為可選

              m_Buttons[ButtonCount].fsStyle=TBSTYLE_BUTTON;

              //設置工具欄按鈕為普通按鈕

              m_Buttons[ButtonCount].dwData=0;

              m_Buttons[ButtonCount].iString=IDS_LAST;

               ++ButtonCount;

              //類似地設置第二個按鈕

              m_Buttons[ButtonCount].iBitmap=ButtonBitmap+ButtonCount;

              m_Buttons[ButtonCount].idCommand=ID_STOP;

              m_Buttons[ButtonCount].fsState=TBSTATE_ENABLED;

              m_Buttons[ButtonCount].fsStyle=TBSTYLE_BUTTON;

              m_Buttons[ButtonCount].dwData=0;

              m_Buttons[ButtonCount].iString=IDS_NEXT;

              ++ButtonCount;

              ……//省略設置剩下的按鈕的代碼

               ToolBar.AddButtons(ButtonCount,m_Buttons);

              //為工具欄加入按鈕并顯示在對話框中

               return TRUE;

              }

              //當鼠標在工具欄上停留時,調用這個函數來顯示提示信息

              BOOL CToolBarInDialDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)

              {

              TOOLTIPTEXT* tt;

              tt=(TOOLTIPTEXT*)lParam;

              CString Tip;

              switch(tt->hdr.code)

              {

              case TTN_NEEDTEXT:

              //該信息表明要求顯示工具欄上的提示

              switch(tt->hdr.idFrom)

              {

              case ID_PLAY:



              Tip.LoadString(IDS_FIRST); //設置對應于工具欄上ID_PLAY的按鈕的提示信息

              break;

              case ID_STOP:

              Tip.LoadString(IDS_NEXT);

              //IDS_FIRST,IDS_NEXT等為一系列CString串

              break;

              ……//類似地設置剩下按鈕的提示信息

              }

               strcpy(tt->szText,(LPCSTR)Tip);

               //顯示提示信息

              break;

              }

              return CDialog::OnNotify(wParam, lParam, pResult);

              }

              //該演示程序的工具欄能由用戶定制,隨時增加或刪除工具欄中的某一項

              void CToolBarInDialDlg::OnApply()

              {

               switch(DoFlag) //用戶選擇了增加或刪除工具欄中的“退出”按鈕

              {

              case TRUE: //增加工具欄上的“退出”按鈕

              m_Buttons[ButtonCount].iBitmap=ButtonBitmap+ButtonCount;

              m_Buttons[ButtonCount].idCommand=ID_QUIT;

              m_Buttons[ButtonCount].fsState=TBSTATE_ENABLED;

              m_Buttons[ButtonCount].fsStyle=TBSTYLE_BUTTON;

              m_Buttons[ButtonCount].dwData=0;

              m_Buttons[ButtonCount].iString=IDS_FIRST;

              ToolBar.InsertButton(ButtonCount,&&m_Buttons[ButtonCount]);

              //根據m_Buttons的信息在工具欄的尾部加上一個按鈕

              break;

              case FALSE:

              if(ToolBar.GetButtonCount()==4) //刪除工具欄上某一特定位置的按鈕

              {

              ToolBar.DeleteButton(3);

              //刪除工具欄上某一按鈕

              }

              break;

              }

              }

              void CToolBarInDialDlg::OnPlay() //響應函數舉例

              {

              ……

              //對應選單項的響應函數

              }
            posted @ 2010-08-01 09:44 張貴川 閱讀(1017) | 評論 (0)編輯 收藏

            安裝步驟其實很簡單,但是你不知道的話,就真的不會。
            1.創建虛擬機,選擇光盤鏡像。
            2.啟動后會讓分區。分區時會讓你重啟。
            3.重啟后按F2進入虛擬機中的BIOS設置為光盤啟動。
            4.進去后就可以了。一路安裝。
            5.安裝完后再次進入BIOS,設置啟動為 硬盤 啟動。

            接著在教你怎樣用虛擬機和DOS共享文件:(源自gagbage同學制作)
            /Files/Viking/share.pdf
            posted @ 2010-07-24 08:51 張貴川 閱讀(252) | 評論 (0)編輯 收藏

            大學生活過的挺失敗的,我是個不甘心落后的人,在技術上,我不認為自己比別人差,然而我卻沒有做出什么成績出來。
             究其原因,我發現:我太浮躁了!
            每門技術我都學了一半,沒有堅持下去。做的也不認真。才造成了我現在半杯水的樣子。看真周圍的同學都成功的做出了很多作品。并且能賺到錢了,就感到了什么叫壓力。
            每門技術都很深奧,每門技術卻又是那樣的誘人,你會什么都想學,什么都想深入,然而卻沒有時間,總是被其他事情打斷學習進程。從大二接觸到學習匯編,玩LINUX,卻沒有堅持下來。大二下有玩單片機和FPGA,但在硬件的基礎課程上模電和數字邏輯上學的是在是太爛,最終也放棄了。我就沒想過認真的去復習一下課程。后面接觸了MFC,又是從0開始學起,為了圖快,便只看書,程序寫的少的,基礎沒打的結實,花費了大量的時間然而卻沒有成果。
            后來遇到了一群驅動愛好著,終于理解到什么叫做學習的氛圍,一個人學習真的是很累人,進步很慢。也終于理解了為什么布施定律是成功之道。
            當然自己也終結了很多的學習方法,但最重要的一條還是:技術的路上踏實認真才是捷徑。
            同時發現數學課程是多么的重要。
            同時發現自己浪費了好多時間在女孩的身上,結果她們最后的話都是不想談戀愛。我決定以后談戀愛都找女人,胸部至少有明顯的突出,這樣的女人談戀愛會更容易些交互些(母性特征)。
            還有男人成熟的開始:就是開始想賺錢買車,買房的時候。
            我是看到我同學這學期都賺錢買車,買房和女友出去同居了,才意識到這些東西。想想,自己真的太浮躁,不認真,浪費了太多認真積累的時間,真的太失敗!
            大家有幸看到我的帖子的話,記住只要選好一個你喜歡的方向,踏實認真的專研下去就可以了,因為沒門技術都很深奧,你沒有那么多的時間成為全才,看看你自己究竟學了什么東西!至于他踏實認真的方法,因個體而異。
             我目前認為最踏實的方法就是
            1.認認真真總結每章所學的內容,可以放到自己的blog上,也可以找個筆記本來認真做筆記,現在才深刻認識到寫好字的重要性。
            2.課后習題每一題都要認真做,最好把答案都發布到自己的blog上。
            3.系統的學習。不要介意你從0開始看,簡單就看快一點,不能不看。
            4.慢即是快。不要浮躁,你不可能是全才,找準一個方向,不要總是換。一本書一本書的看,認真看完一本在看下一本。相信自己是正確的。因為厚積才能薄發。
            posted @ 2010-07-09 11:01 張貴川 閱讀(167) | 評論 (0)編輯 收藏

            assume cs:codeseg
            codeseg segment
                    mov ax,2000H
                    mov ss,ax
                    mov sp,0
                    add sp,4
                    pop ax
                    pop bx
                    push ax
                    push bx
                    pop ax
                    pop bx
                    mov ax,4c00H
                    int 21h
            codeseg ends
            end

            按理來說是DOS中沒有棧保護的啊?怎么會就溢出了呢?

            經過大量的調試測試:

            我試過了,只有ADD SP,N

            N <= 10H

            并且 N = 奇數 的時候就會崩潰


            偶數不崩潰?

            N >= 10H  的時候,奇偶都可以
            N=7,9,B就直接崩潰
            偶數在<=4就觸發 DEBUG 的斷點中斷 INT 3中斷

            可能關乎 16位機的取數原則:16位機取每次取2個字節,并且最好取偶數地址,取奇數地址則要讀取內存2次。意思是棧中的內存SP地址(包括DI,SI等)最好是2的倍數(16位機),這樣訪存時間最快。32則是4的倍數。

            但是為什么會崩潰我還是不明白??
            posted @ 2010-06-29 16:19 張貴川 閱讀(229) | 評論 (0)編輯 收藏

            在使用  重疊IO模型 的時候遇到一個連個 頭文件 包含錯誤,windows.h 和 winsock2.h。在網上找到一篇文章,覺得方法很好,特轉載:

            在我初學Windows網絡編程時,曾經遇到過兩類編譯錯誤(VC6的Build窗口嘩嘩的顯示了102個Errors),都是些類型未定義或者重復定義問題,讓我感到很郁悶。這兩種錯誤情況下的第一條錯誤信息分別為:

            錯誤情形1:mswsock.h(69) : error C2065: 'SOCKET' : undeclared identifier
            錯誤情形2:winsock2.h(99) : error C2011: 'fd_set' : 'struct' type redefinition
            后來,我靜下心來仔細分析一下錯誤提示及相關文件,終于找到了原因。

            我們知道,Windows網絡編程至少需要兩個頭文件:winsock2.h和windows.h,而在WinSock2.0之前還存在一個老版本的winsock.h。正是這三個頭文件的包含順序,導致了上述問題的出現。

            先讓我們看看winsock2.h的內容,在文件開頭有如下宏定義:

            #ifndef _WINSOCK2API_
            #define _WINSOCK2API_
            #define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
            _WINSOCK2API_很容易理解,這是最常見的防止頭文件重復包含的保護措施。_WINSOCKAPI_的定義則是為了阻止對老文件winsock.h的包含,即是說,如果用戶先包含了winsock2.h就不允許再包含winsock.h了,否則會導致類型重復定義。這是怎樣做到的呢?很簡單,因為winsock.h的頭部同樣存在如下的保護措施:

            #ifndef _WINSOCKAPI_
            #define _WINSOCKAPI_
            再回過頭來看winsock2.h,在上述內容之后緊跟著如下宏指令:

            /*
             * Pull in WINDOWS.H if necessary
             */
            #ifndef _INC_WINDOWS
            #include <windows.h>
            #endif /* _INC_WINDOWS */
            其作用是如果用戶沒有包含windows.h(_INC_WINDOWS在windows.h中定義)就自動包含它,以定義WinSock2.0所需的類型和常量等。

            現在切換到windows.h,查找winsock,我們會驚奇的發現以下內容:

            #ifndef WIN32_LEAN_AND_MEAN
            #include <cderr.h>
            #include <dde.h>
            #include <ddeml.h>
            #include <dlgs.h>
            #ifndef _MAC
            #include <lzexpand.h>
            #include <mmsystem.h>
            #include <nb30.h>
            #include <rpc.h>
            #endif
            #include <shellapi.h>
            #ifndef _MAC
            #include <winperf.h>
            #if(_WIN32_WINNT >= 0x0400)
            #include <winsock2.h>
            #include <mswsock.h>
            #else
            #include <winsock.h>
            #endif /* _WIN32_WINNT >=  0x0400 */

            #endif
            // 這里省略掉一部分內容
            #endif /* WIN32_LEAN_AND_MEAN */

            看到沒?windows.h會反向包含winsock2.h或者winsock.h!相互間的包含便是萬惡之源!

            下面具體分析一下問題是怎么發生的。

            錯誤情形1:我們在自己的工程中先包含winsock2.h再包含windows.h,如果WIN32_LEAN_AND_MEAN未定義且_WIN32_WINNT大于或等于0x400,那么windows.h會在winsock2.h開頭被自動引入,而windows.h又會自動引入mswsock.h,此時,mswsock.h里所用的socket類型還尚未定義,因此會出現類型未定義錯誤。

            錯誤情形2:先包含windows.h再包含winsock2.h,如果WIN32_LEAN_AND_MEAN未定義且_WIN32_WINNT未定義或者其版本號小于0x400,那么windows.h會自動導入舊有的winsock.h,這樣再當winsock2.h被包含時便會引起重定義。

            這里要說明的是,宏WIN32_LEAN_AND_MEAN的作用是減小win32頭文件尺寸以加快編譯速度,一般由AppWizard在stdafx.h中自動定義。_WIN32_WINNT的作用是開啟高版本操作系統下的特殊函數,比如要使用可等待定時器(WaitableTimer),就得要求_WIN32_WINNT的值大于或等于0x400。因此,如果你沒有遇到上述兩個問題,很可能是你沒有在這些條件下進行網絡編程。

            問題還沒有結束,要知道除了VC自帶windows庫文件外,MS的Platform SDK也含有這些頭文件。我們很可能發現在之前能夠好好編譯的程序在改變了windows頭文件包含路徑后又出了問題。原因很簡單,Platform SDK中的windows.h與VC自帶的文件存在差異,其相同位置的代碼如下:

            #ifndef WIN32_LEAN_AND_MEAN
            #include <cderr.h>
            #include <dde.h>
            #include <ddeml.h>
            #include <dlgs.h>
            #ifndef _MAC
            #include <lzexpand.h>
            #include <mmsystem.h>
            #include <nb30.h>
            #include <rpc.h>
            #endif
            #include <shellapi.h>
            #ifndef _MAC
            #include <winperf.h>
            #include <winsock.h>  // 這里直接包含winsock.h
            #endif
            #ifndef NOCRYPT
            #include <wincrypt.h>
            #include <winefs.h>
            #include <winscard.h>
            #endif
            #ifndef NOGDI
            #ifndef _MAC
            #include <winspool.h>
            #ifdef INC_OLE1
            #include <ole.h>
            #else
            #include <ole2.h>
            #endif /* !INC_OLE1 */
            #endif /* !MAC */
            #include <commdlg.h>
            #endif /* !NOGDI */
            #endif /* WIN32_LEAN_AND_MEAN */

            唉,我們不禁要問MS為什么要搞這么多花樣,更讓人氣憤的是,既然代碼不一樣,windows.h里卻沒有任何一個宏定義能夠幫助程序辨別當前使用的文件是VC自帶的還是PSDK里的。

            后來,我寫了一個頭文件專門處理winsock2.h的包含問題,名為winsock2i.h,只需在要使用WinSock2.0的源文件里第一個包含此文件即可,不過由于前面提到的問題,當使用PSDK時,需要手工定義一下USING_WIN_PSDK,源碼如下:

            //
            // winsock2i.h - Include winsock2.h safely.
            //
            // Copyleft  02/24/2005  by freefalcon
            //
            //
            // When WIN32_LEAN_AND_MEAN is not defined and _WIN32_WINNT is LESS THAN 0x400,
            // if we include winsock2.h AFTER windows.h or winsock.h, we get some compiling
            // errors as following:
            //   winsock2.h(99) : error C2011: 'fd_set' : 'struct' type redefinition
            //
            // When WIN32_LEAN_AND_MEAN is not defined and _WIN32_WINNT is NOT LESS THAN 0x400,
            // if we include winsock2.h BEFORE windows.h, we get some other compiling errors:
            //   mswsock.h(69) : error C2065: 'SOCKET' : undeclared identifier
            //
            // So, this file is used to help us to include winsock2.h safely, it should be
            // placed before any other header files.
            //
            #ifndef _WINSOCK2API_

            // Prevent inclusion of winsock.h
            #ifdef _WINSOCKAPI_
            #error Header winsock.h is included unexpectedly.
            #endif

            // NOTE: If you use Windows Platform SDK, you should enable following definition:
            // #define USING_WIN_PSDK

            #if !defined(WIN32_LEAN_AND_MEAN) && (_WIN32_WINNT >= 0x0400) && !defined(USING_WIN_PSDK)
            #include <windows.h>
            #else
            #include <winsock2.h>
            #endif

            #endif//_WINSOCK2API_

            本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/freefalcon/archive/2006/11/09/1374733.aspx

            按照freefalcon提供的方法,到winsock2.h中看到:
            #ifndef _INC_WINDOWS
            #include <windows.h>
            #endif /* _INC_WINDOWS */
            其實只需包含#include <winsock2.h>就可以了,把#include <windows.h>放在#include <winsock2.h>后其實也是可以的,沒有包含錯誤的問題。

            但如果又出現這樣的錯誤:
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__closesocket@4,該符號在函數 _main 中被引用
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__WSAGetLastError@0,該符號在函數 _main 中被引用
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__WSARecv@28,該符號在函數 _main 中被引用
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__WSACreateEvent@0,該符號在函數 _main 中被引用
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__accept@12,該符號在函數 _main 中被引用
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__listen@8,該符號在函數 _main 中被引用
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__bind@12,該符號在函數 _main 中被引用
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__htons@4,該符號在函數 _main 中被引用
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__htonl@4,該符號在函數 _main 中被引用
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__socket@12,該符號在函數 _main 中被引用
            1>server.obj : error LNK2019: 無法解析的外部符號 __imp__WSAStartup@8,該符號在函數 _main 中被引用

            如果出現這樣的錯誤,那就是庫沒包含了,只要查查MSDN,找到包含這個函數的庫就行了,加入一句:

            #pragma   comment(lib,   "ws2_32.lib")

            posted @ 2010-05-18 20:51 張貴川 閱讀(1048) | 評論 (0)編輯 收藏

            剛遇到一個問題,在MFC中我將映射方式由 MM_TEXT 改為 MM_HIENGLISH 后,竟然無法輸出漢字!!但改回 MM_TEXT 后就可以輸出漢字了。
            這個問題很郁悶,找了很久也不知道是怎么回事....暫時先記在這里。。。

            posted @ 2010-05-16 22:17 張貴川 閱讀(93) | 評論 (0)編輯 收藏

            僅列出標題
            共5頁: 1 2 3 4 5 
            久久综合久久综合九色| 国产精品成人久久久久久久| 99久久国产综合精品五月天喷水 | 日韩欧美亚洲综合久久影院d3| 色婷婷久久综合中文久久蜜桃av| 欧洲成人午夜精品无码区久久| 99久久国产热无码精品免费| 久久精品免费观看| 久久99精品免费一区二区| 久久福利资源国产精品999| 欧美牲交A欧牲交aⅴ久久| 久久久久人妻一区精品果冻| 久久久精品人妻一区二区三区蜜桃| 国产精品亚洲综合专区片高清久久久 | 久久成人影院精品777| 97视频久久久| 久久国产三级无码一区二区| 一本色道久久综合狠狠躁| 欧美亚洲另类久久综合婷婷| 久久99精品国产99久久6| 99国产精品久久久久久久成人热| 少妇高潮惨叫久久久久久| 一本色综合久久| 久久婷婷人人澡人人爽人人爱 | 99久久精品免费看国产一区二区三区| 久久这里只有精品首页| 91精品国产91久久久久久| 久久亚洲国产精品一区二区| 久久激情五月丁香伊人| 亚洲精品无码久久不卡| 久久夜色精品国产噜噜亚洲AV| 久久人人爽人人爽人人AV东京热| 精品国产乱码久久久久久郑州公司 | 久久综合九色综合97_久久久| 国产—久久香蕉国产线看观看 | 久久久久亚洲av成人无码电影| 一本久久综合亚洲鲁鲁五月天亚洲欧美一区二区| 国产精品美女久久久久av爽 | av无码久久久久久不卡网站| 久久精品亚洲乱码伦伦中文| 日产精品久久久久久久|