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

            road420

            導(dǎo)航

            <2025年8月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            統(tǒng)計(jì)

            常用鏈接

            留言簿(2)

            隨筆檔案

            文章檔案

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            #

            堆~棧區(qū)別

            來(lái)自任我行C++blog:


            堆和棧的區(qū)別
            一、預(yù)備知識(shí)—程序的內(nèi)存分配
            一個(gè)由c/C++編譯的程序占用的內(nèi)存分為以下幾個(gè)部分
            1、棧區(qū)(stack)— 由編譯器自動(dòng)分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類(lèi)似于數(shù)據(jù)結(jié)構(gòu)中的棧。
            2、堆區(qū)(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類(lèi)似于鏈表,呵呵。
            3、全局區(qū)(靜態(tài)區(qū))(static)—,全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。 - 程序結(jié)束后有系統(tǒng)釋放 
            4、文字常量區(qū)—常量字符串就是放在這里的。 程序結(jié)束后由系統(tǒng)釋放
            5、程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。
            二、例子程序 
            這是一個(gè)前輩寫(xiě)的,非常詳細(xì) 
            //main.cpp 
            int a = 0; 全局初始化區(qū) 
            char *p1; 全局未初始化區(qū) 
            main() 

            int b; 棧 
            char s[] = "abc"; 棧 
            char *p2; 棧 
            char *p3 = "123456"; 123456\0在常量區(qū),p3在棧上。 
            static int c =0; 全局(靜態(tài))初始化區(qū) 
            p1 = (char *)malloc(10); 
            p2 = (char *)malloc(20); 
            分配得來(lái)得10和20字節(jié)的區(qū)域就在堆區(qū)。 
            strcpy(p1, "123456"); 123456\0放在常量區(qū),編譯器可能會(huì)將它與p3所指向的"123456"優(yōu)化成一個(gè)地方。 

             


            二、堆和棧的理論知識(shí) 
            2.1申請(qǐng)方式 
            stack: 
            由系統(tǒng)自動(dòng)分配。 例如,聲明在函數(shù)中一個(gè)局部變量 int b; 系統(tǒng)自動(dòng)在棧中為b開(kāi)辟空間 
            heap: 
            需要程序員自己申請(qǐng),并指明大小,在c中malloc函數(shù) 
            如p1 = (char *)malloc(10); 
            在C++中用new運(yùn)算符 
            如p2 = (char *)malloc(10); 
            但是注意p1、p2本身是在棧中的。 


            2.2 
            申請(qǐng)后系統(tǒng)的響應(yīng) 
            棧:只要棧的剩余空間大于所申請(qǐng)空間,系統(tǒng)將為程序提供內(nèi)存,否則將報(bào)異常提示棧溢出。 
            堆:首先應(yīng)該知道操作系統(tǒng)有一個(gè)記錄空閑內(nèi)存地址的鏈表,當(dāng)系統(tǒng)收到程序的申請(qǐng)時(shí), 
            會(huì)遍歷該鏈表,尋找第一個(gè)空間大于所申請(qǐng)空間的堆結(jié)點(diǎn),然后將該結(jié)點(diǎn)從空閑結(jié)點(diǎn)鏈表中刪除,并將該結(jié)點(diǎn)的空間分配給程序,另外,對(duì)于大多數(shù)系統(tǒng),會(huì)在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語(yǔ)句才能正確的釋放本內(nèi)存空間。另外,由于找到的堆結(jié)點(diǎn)的大小不一定正好等于申請(qǐng)的大小,系統(tǒng)會(huì)自動(dòng)的將多余的那部分重新放入空閑鏈表中。 

            2.3申請(qǐng)大小的限制 
            棧:在Windows下,棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在WINDOWS下,棧的大小是2M(也有的說(shuō)是1M,總之是一個(gè)編譯時(shí)就確定的常數(shù)),如果申請(qǐng)的空間超過(guò)棧的剩余空間時(shí),將提示overflow。因此,能從棧獲得的空間較小。 
            堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來(lái)存儲(chǔ)的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見(jiàn),堆獲得的空間比較靈活,也比較大。 


            2.4申請(qǐng)效率的比較: 
            棧由系統(tǒng)自動(dòng)分配,速度較快。但程序員是無(wú)法控制的。 
            堆是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過(guò)用起來(lái)最方便. 
            另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內(nèi)存,他不是在堆,也不是在棧是直接在進(jìn)程的地址空間中保留一快內(nèi)存,雖然用起來(lái)最不方便。但是速度快,也最靈活。 

            2.5堆和棧中的存儲(chǔ)內(nèi)容 
            棧: 在函數(shù)調(diào)用時(shí),第一個(gè)進(jìn)棧的是主函數(shù)中后的下一條指令(函數(shù)調(diào)用語(yǔ)句的下一條可執(zhí)行語(yǔ)句)的地址,然后是函數(shù)的各個(gè)參數(shù),在大多數(shù)的C編譯器中,參數(shù)是由右往左入棧的,然后是函數(shù)中的局部變量。注意靜態(tài)變量是不入棧的。 
            當(dāng)本次函數(shù)調(diào)用結(jié)束后,局部變量先出棧,然后是參數(shù),最后棧頂指針指向最開(kāi)始存的地址,也就是主函數(shù)中的下一條指令,程序由該點(diǎn)繼續(xù)運(yùn)行。 
            堆:一般是在堆的頭部用一個(gè)字節(jié)存放堆的大小。堆中的具體內(nèi)容有程序員安排。 

            2.6存取效率的比較 

            char s1[] = "aaaaaaaaaaaaaaa"; 
            char *s2 = "bbbbbbbbbbbbbbbbb"; 
            aaaaaaaaaaa是在運(yùn)行時(shí)刻賦值的; 
            而bbbbbbbbbbb是在編譯時(shí)就確定的; 
            但是,在以后的存取中,在棧上的數(shù)組比指針?biāo)赶虻淖址?例如堆)快。 
            比如: 
            #include 
            void main() 

            char a = 1; 
            char c[] = "1234567890"; 
            char *p ="1234567890"; 
            a = c[1]; 
            a = p[1]; 
            return; 

            對(duì)應(yīng)的匯編代碼 
            10: a = c[1]; 
            00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] 
            0040106A 88 4D FC mov byte ptr [ebp-4],cl 
            11: a = p[1]; 
            0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] 
            00401070 8A 42 01 mov al,byte ptr [edx+1] 
            00401073 88 45 FC mov byte ptr [ebp-4],al 
            第一種在讀取時(shí)直接就把字符串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到edx中,在根據(jù)edx讀取字符,顯然慢了。 


            2.7小結(jié): 
            堆和棧的區(qū)別可以用如下的比喻來(lái)看出: 
            使用棧就象我們?nèi)ワ堭^里吃飯,只管點(diǎn)菜(發(fā)出申請(qǐng))、付錢(qián)、和吃(使用),吃飽了就走,不必理會(huì)切菜、洗菜等準(zhǔn)備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。 
            使用堆就象是自己動(dòng)手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。 



            windows進(jìn)程中的內(nèi)存結(jié)構(gòu)


            在閱讀本文之前,如果你連堆棧是什么多不知道的話,請(qǐng)先閱讀文章后面的基礎(chǔ)知識(shí)。 

            接觸過(guò)編程的人都知道,高級(jí)語(yǔ)言都能通過(guò)變量名來(lái)訪問(wèn)內(nèi)存中的數(shù)據(jù)。那么這些變量在內(nèi)存中是如何存放的呢?程序又是如何使用這些變量的呢?下面就會(huì)對(duì)此進(jìn)行深入的討論。下文中的C語(yǔ)言代碼如沒(méi)有特別聲明,默認(rèn)都使用VC編譯的release版。 

            首先,來(lái)了解一下 C 語(yǔ)言的變量是如何在內(nèi)存分部的。C 語(yǔ)言有全局變量(Global)、本地變量(Local),靜態(tài)變量(Static)、寄存器變量(Regeister)。每種變量都有不同的分配方式。先來(lái)看下面這段代碼: 

            #include <stdio.h> 

            int g1=0, g2=0, g3=0; 

            int main() 

            static int s1=0, s2=0, s3=0; 
            int v1=0, v2=0, v3=0; 

            //打印出各個(gè)變量的內(nèi)存地址 

            printf("0x%08x\n",&v1); //打印各本地變量的內(nèi)存地址 
            printf("0x%08x\n",&v2); 
            printf("0x%08x\n\n",&v3); 
            printf("0x%08x\n",&g1); //打印各全局變量的內(nèi)存地址 
            printf("0x%08x\n",&g2); 
            printf("0x%08x\n\n",&g3); 
            printf("0x%08x\n",&s1); //打印各靜態(tài)變量的內(nèi)存地址 
            printf("0x%08x\n",&s2); 
            printf("0x%08x\n\n",&s3); 
            return 0; 

            編譯后的執(zhí)行結(jié)果是: 

            0x0012ff78 
            0x0012ff7c 
            0x0012ff80 

            0x004068d0 
            0x004068d4 
            0x004068d8 

            0x004068dc 
            0x004068e0 
            0x004068e4 

            輸出的結(jié)果就是變量的內(nèi)存地址。其中v1,v2,v3是本地變量,g1,g2,g3是全局變量,s1,s2,s3是靜態(tài)變量。你可以看到這些變量在內(nèi)存是連續(xù)分布的,但是本地變量和全局變量分配的內(nèi)存地址差了十萬(wàn)八千里,而全局變量和靜態(tài)變量分配的內(nèi)存是連續(xù)的。這是因?yàn)楸镜刈兞亢腿?靜態(tài)變量是分配在不同類(lèi)型的內(nèi)存區(qū)域中的結(jié)果。對(duì)于一個(gè)進(jìn)程的內(nèi)存空間而言,可以在邏輯上分成3個(gè)部份:代碼區(qū),靜態(tài)數(shù)據(jù)區(qū)和動(dòng)態(tài)數(shù)據(jù)區(qū)。動(dòng)態(tài)數(shù)據(jù)區(qū)一般就是“堆棧”。“棧(stack)”和“堆(heap)”是兩種不同的動(dòng)態(tài)數(shù)據(jù)區(qū),棧是一種線性結(jié)構(gòu),堆是一種鏈?zhǔn)浇Y(jié)構(gòu)。進(jìn)程的每個(gè)線程都有私有的“棧”,所以每個(gè)線程雖然代碼一樣,但本地變量的數(shù)據(jù)都是互不干擾。一個(gè)堆棧可以通過(guò)“基地址”和“棧頂”地址來(lái)描述。全局變量和靜態(tài)變量分配在靜態(tài)數(shù)據(jù)區(qū),本地變量分配在動(dòng)態(tài)數(shù)據(jù)區(qū),即堆棧中。程序通過(guò)堆棧的基地址和偏移量來(lái)訪問(wèn)本地變量。 


            ├———————┤低端內(nèi)存區(qū)域 
            │ …… │ 
            ├———————┤ 
            │ 動(dòng)態(tài)數(shù)據(jù)區(qū) │ 
            ├———————┤ 
            │ …… │ 
            ├———————┤ 
            │ 代碼區(qū) │ 
            ├———————┤ 
            │ 靜態(tài)數(shù)據(jù)區(qū) │ 
            ├———————┤ 
            │ …… │ 
            ├———————┤高端內(nèi)存區(qū)域 


            堆棧是一個(gè)先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),棧頂?shù)刂房偸切∮诘扔跅5幕刂贰N覀兛梢韵攘私庖幌潞瘮?shù)調(diào)用的過(guò)程,以便對(duì)堆棧在程序中的作用有更深入的了解。不同的語(yǔ)言有不同的函數(shù)調(diào)用規(guī)定,這些因素有參數(shù)的壓入規(guī)則和堆棧的平衡。windows API的調(diào)用規(guī)則和ANSI C的函數(shù)調(diào)用規(guī)則是不一樣的,前者由被調(diào)函數(shù)調(diào)整堆棧,后者由調(diào)用者調(diào)整堆棧。兩者通過(guò)“__stdcall”和“__cdecl”前綴區(qū)分。先看下面這段代碼: 

            #include <stdio.h> 

            void __stdcall func(int param1,int param2,int param3) 

            int var1=param1; 
            int var2=param2; 
            int var3=param3; 
            printf("0x%08x\n",¶m1); //打印出各個(gè)變量的內(nèi)存地址 
            printf("0x%08x\n",¶m2); 
            printf("0x%08x\n\n",¶m3); 
            printf("0x%08x\n",&var1); 
            printf("0x%08x\n",&var2); 
            printf("0x%08x\n\n",&var3); 
            return; 

            int main() 

            func(1,2,3); 
            return 0; 

            編譯后的執(zhí)行結(jié)果是: 

            0x0012ff78 
            0x0012ff7c 
            0x0012ff80 

            0x0012ff68 
            0x0012ff6c 
            0x0012ff70 


            ├———————┤<—函數(shù)執(zhí)行時(shí)的棧頂(ESP)、低端內(nèi)存區(qū)域 
            │ …… │ 
            ├———————┤ 
            │ var 1 │ 
            ├———————┤ 
            │ var 2 │ 
            ├———————┤ 
            │ var 3 │ 
            ├———————┤ 
            │ RET │ 
            ├———————┤<—“__cdecl”函數(shù)返回后的棧頂(ESP) 
            │ parameter 1 │ 
            ├———————┤ 
            │ parameter 2 │ 
            ├———————┤ 
            │ parameter 3 │ 
            ├———————┤<—“__stdcall”函數(shù)返回后的棧頂(ESP) 
            │ …… │ 
            ├———————┤<—棧底(基地址 EBP)、高端內(nèi)存區(qū)域 


            上圖就是函數(shù)調(diào)用過(guò)程中堆棧的樣子了。首先,三個(gè)參數(shù)以從又到左的次序壓入堆棧,先壓“param3”,再壓“param2”,最后壓入“param1”;然后壓入函數(shù)的返回地址(RET),接著跳轉(zhuǎn)到函數(shù)地址接著執(zhí)行(這里要補(bǔ)充一點(diǎn),介紹UNIX下的緩沖溢出原理的文章中都提到在壓入RET后,繼續(xù)壓入當(dāng)前EBP,然后用當(dāng)前ESP代替EBP。然而,有一篇介紹windows下函數(shù)調(diào)用的文章中說(shuō),在windows下的函數(shù)調(diào)用也有這一步驟,但根據(jù)我的實(shí)際調(diào)試,并未發(fā)現(xiàn)這一步,這還可以從param3和var1之間只有4字節(jié)的間隙這點(diǎn)看出來(lái));第三步,將棧頂(ESP)減去一個(gè)數(shù),為本地變量分配內(nèi)存空間,上例中是減去12字節(jié)(ESP=ESP-3*4,每個(gè)int變量占用4個(gè)字節(jié));接著就初始化本地變量的內(nèi)存空間。由于“__stdcall”調(diào)用由被調(diào)函數(shù)調(diào)整堆棧,所以在函數(shù)返回前要恢復(fù)堆棧,先回收本地變量占用的內(nèi)存(ESP=ESP+3*4),然后取出返回地址,填入EIP寄存器,回收先前壓入?yún)?shù)占用的內(nèi)存(ESP=ESP+3*4),繼續(xù)執(zhí)行調(diào)用者的代碼。參見(jiàn)下列匯編代碼: 

            ;--------------func 函數(shù)的匯編代碼------------------- 

            :00401000 83EC0C sub esp, 0000000C //創(chuàng)建本地變量的內(nèi)存空間 
            :00401003 8B442410 mov eax, dword ptr [esp+10] 
            :00401007 8B4C2414 mov ecx, dword ptr [esp+14] 
            :0040100B 8B542418 mov edx, dword ptr [esp+18] 
            :0040100F 89442400 mov dword ptr [esp], eax 
            :00401013 8D442410 lea eax, dword ptr [esp+10] 
            :00401017 894C2404 mov dword ptr [esp+04], ecx 

            ……………………(省略若干代碼) 

            :00401075 83C43C add esp, 0000003C ;恢復(fù)堆棧,回收本地變量的內(nèi)存空間 
            :00401078 C3 ret 000C ;函數(shù)返回,恢復(fù)參數(shù)占用的內(nèi)存空間 
            ;如果是“__cdecl”的話,這里是“ret”,堆棧將由調(diào)用者恢復(fù) 

            ;-------------------函數(shù)結(jié)束------------------------- 


            ;--------------主程序調(diào)用func函數(shù)的代碼-------------- 

            :00401080 6A03 push 00000003 //壓入?yún)?shù)param3 
            :00401082 6A02 push 00000002 //壓入?yún)?shù)param2 
            :00401084 6A01 push 00000001 //壓入?yún)?shù)param1 
            :00401086 E875FFFFFF call 00401000 //調(diào)用func函數(shù) 
            ;如果是“__cdecl”的話,將在這里恢復(fù)堆棧,“add esp, 0000000C” 

            聰明的讀者看到這里,差不多就明白緩沖溢出的原理了。先來(lái)看下面的代碼: 

            #include <stdio.h> 
            #include <string.h> 

            void __stdcall func() 

            char lpBuff[8]="\0"; 
            strcat(lpBuff,"AAAAAAAAAAA"); 
            return; 

            int main() 

            func(); 
            return 0; 

            編譯后執(zhí)行一下回怎么樣?哈,“"0x00414141"指令引用的"0x00000000"內(nèi)存。該內(nèi)存不能為"read"。”,“非法操作”嘍!"41"就是"A"的16進(jìn)制的ASCII碼了,那明顯就是strcat這句出的問(wèn)題了。"lpBuff"的大小只有8字節(jié),算進(jìn)結(jié)尾的\0,那strcat最多只能寫(xiě)入7個(gè)"A",但程序?qū)嶋H寫(xiě)入了11個(gè)"A"外加1個(gè)\0。再來(lái)看看上面那幅圖,多出來(lái)的4個(gè)字節(jié)正好覆蓋了RET的所在的內(nèi)存空間,導(dǎo)致函數(shù)返回到一個(gè)錯(cuò)誤的內(nèi)存地址,執(zhí)行了錯(cuò)誤的指令。如果能精心構(gòu)造這個(gè)字符串,使它分成三部分,前一部份僅僅是填充的無(wú)意義數(shù)據(jù)以達(dá)到溢出的目的,接著是一個(gè)覆蓋RET的數(shù)據(jù),緊接著是一段shellcode,那只要著個(gè)RET地址能指向這段shellcode的第一個(gè)指令,那函數(shù)返回時(shí)就能執(zhí)行shellcode了。但是軟件的不同版本和不同的運(yùn)行環(huán)境都可能影響這段shellcode在內(nèi)存中的位置,那么要構(gòu)造這個(gè)RET是十分困難的。一般都在RET和shellcode之間填充大量的NOP指令,使得exploit有更強(qiáng)的通用性。 


            ├———————┤<—低端內(nèi)存區(qū)域 
            │ …… │ 
            ├———————┤<—由exploit填入數(shù)據(jù)的開(kāi)始 
            │ │ 
            │ buffer │<—填入無(wú)用的數(shù)據(jù) 
            │ │ 
            ├———————┤ 
            │ RET │<—指向shellcode,或NOP指令的范圍 
            ├———————┤ 
            │ NOP │ 
            │ …… │<—填入的NOP指令,是RET可指向的范圍 
            │ NOP │ 
            ├———————┤ 
            │ │ 
            │ shellcode │ 
            │ │ 
            ├———————┤<—由exploit填入數(shù)據(jù)的結(jié)束 
            │ …… │ 
            ├———————┤<—高端內(nèi)存區(qū)域 


            windows下的動(dòng)態(tài)數(shù)據(jù)除了可存放在棧中,還可以存放在堆中。了解C++的朋友都知道,C++可以使用new關(guān)鍵字來(lái)動(dòng)態(tài)分配內(nèi)存。來(lái)看下面的C++代碼: 

            #include <stdio.h> 
            #include <iostream.h> 
            #include <windows.h> 

            void func() 

            char *buffer=new char[128]; 
            char bufflocal[128]; 
            static char buffstatic[128]; 
            printf("0x%08x\n",buffer); //打印堆中變量的內(nèi)存地址 
            printf("0x%08x\n",bufflocal); //打印本地變量的內(nèi)存地址 
            printf("0x%08x\n",buffstatic); //打印靜態(tài)變量的內(nèi)存地址 

            void main() 

            func(); 
            return; 

            程序執(zhí)行結(jié)果為: 

            0x004107d0 
            0x0012ff04 
            0x004068c0 

            可以發(fā)現(xiàn)用new關(guān)鍵字分配的內(nèi)存即不在棧中,也不在靜態(tài)數(shù)據(jù)區(qū)。VC編譯器是通過(guò)windows下的“堆(heap)”來(lái)實(shí)現(xiàn)new關(guān)鍵字的內(nèi)存動(dòng)態(tài)分配。在講“堆”之前,先來(lái)了解一下和“堆”有關(guān)的幾個(gè)API函數(shù): 

            HeapAlloc 在堆中申請(qǐng)內(nèi)存空間 
            HeapCreate 創(chuàng)建一個(gè)新的堆對(duì)象 
            HeapDestroy 銷(xiāo)毀一個(gè)堆對(duì)象 
            HeapFree 釋放申請(qǐng)的內(nèi)存 
            HeapWalk 枚舉堆對(duì)象的所有內(nèi)存塊 
            GetProcessHeap 取得進(jìn)程的默認(rèn)堆對(duì)象 
            GetProcessHeaps 取得進(jìn)程所有的堆對(duì)象 
            LocalAlloc 
            GlobalAlloc 

            當(dāng)進(jìn)程初始化時(shí),系統(tǒng)會(huì)自動(dòng)為進(jìn)程創(chuàng)建一個(gè)默認(rèn)堆,這個(gè)堆默認(rèn)所占內(nèi)存的大小為1M。堆對(duì)象由系統(tǒng)進(jìn)行管理,它在內(nèi)存中以鏈?zhǔn)浇Y(jié)構(gòu)存在。通過(guò)下面的代碼可以通過(guò)堆動(dòng)態(tài)申請(qǐng)內(nèi)存空間: 

            HANDLE hHeap=GetProcessHeap(); 
            char *buff=HeapAlloc(hHeap,0,8); 

            其中hHeap是堆對(duì)象的句柄,buff是指向申請(qǐng)的內(nèi)存空間的地址。那這個(gè)hHeap究竟是什么呢?它的值有什么意義嗎?看看下面這段代碼吧: 

            #pragma comment(linker,"/entry:main") //定義程序的入口 
            #include <windows.h> 

            _CRTIMP int (__cdecl *printf)(const char *, ...); //定義STL函數(shù)printf 
            /*--------------------------------------------------------------------------- 
            寫(xiě)到這里,我們順便來(lái)復(fù)習(xí)一下前面所講的知識(shí): 
            (*注)printf函數(shù)是C語(yǔ)言的標(biāo)準(zhǔn)函數(shù)庫(kù)中函數(shù),VC的標(biāo)準(zhǔn)函數(shù)庫(kù)由msvcrt.dll模塊實(shí)現(xiàn)。 
            由函數(shù)定義可見(jiàn),printf的參數(shù)個(gè)數(shù)是可變的,函數(shù)內(nèi)部無(wú)法預(yù)先知道調(diào)用者壓入的參數(shù)個(gè)數(shù),函數(shù)只能通過(guò)分析第一個(gè)參數(shù)字符串的格式來(lái)獲得壓入?yún)?shù)的信息,由于這里參數(shù)的個(gè)數(shù)是動(dòng)態(tài)的,所以必須由調(diào)用者來(lái)平衡堆棧,這里便使用了__cdecl調(diào)用規(guī)則。BTW,Windows系統(tǒng)的API函數(shù)基本上是__stdcall調(diào)用形式,只有一個(gè)API例外,那就是wsprintf,它使用__cdecl調(diào)用規(guī)則,同printf函數(shù)一樣,這是由于它的參數(shù)個(gè)數(shù)是可變的緣故。 
            ---------------------------------------------------------------------------*/ 
            void main() 

            HANDLE hHeap=GetProcessHeap(); 
            char *buff=HeapAlloc(hHeap,0,0x10); 
            char *buff2=HeapAlloc(hHeap,0,0x10); 
            HMODULE hMsvcrt=LoadLibrary("msvcrt.dll"); 
            printf=(void *)GetProcAddress(hMsvcrt,"printf"); 
            printf("0x%08x\n",hHeap); 
            printf("0x%08x\n",buff); 
            printf("0x%08x\n\n",buff2); 

            執(zhí)行結(jié)果為: 

            0x00130000 
            0x00133100 
            0x00133118 

            hHeap的值怎么和那個(gè)buff的值那么接近呢?其實(shí)hHeap這個(gè)句柄就是指向HEAP首部的地址。在進(jìn)程的用戶(hù)區(qū)存著一個(gè)叫PEB(進(jìn)程環(huán)境塊)的結(jié)構(gòu),這個(gè)結(jié)構(gòu)中存放著一些有關(guān)進(jìn)程的重要信息,其中在PEB首地址偏移0x18處存放的ProcessHeap就是進(jìn)程默認(rèn)堆的地址,而偏移0x90處存放了指向進(jìn)程所有堆的地址列表的指針。windows有很多API都使用進(jìn)程的默認(rèn)堆來(lái)存放動(dòng)態(tài)數(shù)據(jù),如windows 2000下的所有ANSI版本的函數(shù)都是在默認(rèn)堆中申請(qǐng)內(nèi)存來(lái)轉(zhuǎn)換ANSI字符串到Unicode字符串的。對(duì)一個(gè)堆的訪問(wèn)是順序進(jìn)行的,同一時(shí)刻只能有一個(gè)線程訪問(wèn)堆中的數(shù)據(jù),當(dāng)多個(gè)線程同時(shí)有訪問(wèn)要求時(shí),只能排隊(duì)等待,這樣便造成程序執(zhí)行效率下降。 

            最后來(lái)說(shuō)說(shuō)內(nèi)存中的數(shù)據(jù)對(duì)齊。所位數(shù)據(jù)對(duì)齊,是指數(shù)據(jù)所在的內(nèi)存地址必須是該數(shù)據(jù)長(zhǎng)度的整數(shù)倍,DWORD數(shù)據(jù)的內(nèi)存起始地址能被4除盡,WORD數(shù)據(jù)的內(nèi)存起始地址能被2除盡,x86 CPU能直接訪問(wèn)對(duì)齊的數(shù)據(jù),當(dāng)他試圖訪問(wèn)一個(gè)未對(duì)齊的數(shù)據(jù)時(shí),會(huì)在內(nèi)部進(jìn)行一系列的調(diào)整,這些調(diào)整對(duì)于程序來(lái)說(shuō)是透明的,但是會(huì)降低運(yùn)行速度,所以編譯器在編譯程序時(shí)會(huì)盡量保證數(shù)據(jù)對(duì)齊。同樣一段代碼,我們來(lái)看看用VC、Dev-C++和lcc三個(gè)不同編譯器編譯出來(lái)的程序的執(zhí)行結(jié)果: 

            #include <stdio.h> 

            int main() 

            int a; 
            char b; 
            int c; 
            printf("0x%08x\n",&a); 
            printf("0x%08x\n",&b); 
            printf("0x%08x\n",&c); 
            return 0; 

            這是用VC編譯后的執(zhí)行結(jié)果: 
            0x0012ff7c 
            0x0012ff7b 
            0x0012ff80 
            變量在內(nèi)存中的順序:b(1字節(jié))-a(4字節(jié))-c(4字節(jié))。 

            這是用Dev-C++編譯后的執(zhí)行結(jié)果: 
            0x0022ff7c 
            0x0022ff7b 
            0x0022ff74 
            變量在內(nèi)存中的順序:c(4字節(jié))-中間相隔3字節(jié)-b(占1字節(jié))-a(4字節(jié))。 

            這是用lcc編譯后的執(zhí)行結(jié)果: 
            0x0012ff6c 
            0x0012ff6b 
            0x0012ff64 
            變量在內(nèi)存中的順序:同上。 

            三個(gè)編譯器都做到了數(shù)據(jù)對(duì)齊,但是后兩個(gè)編譯器顯然沒(méi)VC“聰明”,讓一個(gè)char占了4字節(jié),浪費(fèi)內(nèi)存哦。 


            基礎(chǔ)知識(shí): 
            堆棧是一種簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu),是一種只允許在其一端進(jìn)行插入或刪除的線性表。允許插入或刪除操作的一端稱(chēng)為棧頂,另一端稱(chēng)為棧底,對(duì)堆棧的插入和刪除操作被稱(chēng)為入棧和出棧。有一組CPU指令可以實(shí)現(xiàn)對(duì)進(jìn)程的內(nèi)存實(shí)現(xiàn)堆棧訪問(wèn)。其中,POP指令實(shí)現(xiàn)出棧操作,PUSH指令實(shí)現(xiàn)入棧操作。CPU的ESP寄存器存放當(dāng)前線程的棧頂指針,EBP寄存器中保存當(dāng)前線程的棧底指針。CPU的EIP寄存器存放下一個(gè)CPU指令存放的內(nèi)存地址,當(dāng)CPU執(zhí)行完當(dāng)前的指令后,從EIP寄存器中讀取下一條指令的內(nèi)存地址,然后繼續(xù)執(zhí)行。 


            參考:《Windows下的HEAP溢出及其利用》by: isno 
            《windows核心編程》by: Jeffrey Richter 



            摘要: 討論常見(jiàn)的堆性能問(wèn)題以及如何防范它們。(共 9 頁(yè))

            前言
            您是否是動(dòng)態(tài)分配的 C/C++ 對(duì)象忠實(shí)且幸運(yùn)的用戶(hù)?您是否在模塊間的往返通信中頻繁地使用了“自動(dòng)化”?您的程序是否因堆分配而運(yùn)行起來(lái)很慢?不僅僅您遇到這樣的問(wèn)題。幾乎所有項(xiàng)目遲早都會(huì)遇到堆問(wèn)題。大家都想說(shuō),“我的代碼真正好,只是堆太慢”。那只是部分正確。更深入理解堆及其用法、以及會(huì)發(fā)生什么問(wèn)題,是很有用的。

            什么是堆?
            (如果您已經(jīng)知道什么是堆,可以跳到“什么是常見(jiàn)的堆性能問(wèn)題?”部分)

            在程序中,使用堆來(lái)動(dòng)態(tài)分配和釋放對(duì)象。在下列情況下,調(diào)用堆操作: 

            事先不知道程序所需對(duì)象的數(shù)量和大小。


            對(duì)象太大而不適合堆棧分配程序。
            堆使用了在運(yùn)行時(shí)分配給代碼和堆棧的內(nèi)存之外的部分內(nèi)存。下圖給出了堆分配程序的不同層。


            GlobalAlloc/GlobalFree:Microsoft Win32 堆調(diào)用,這些調(diào)用直接與每個(gè)進(jìn)程的默認(rèn)堆進(jìn)行對(duì)話。

            LocalAlloc/LocalFree:Win32 堆調(diào)用(為了與 Microsoft Windows NT 兼容),這些調(diào)用直接與每個(gè)進(jìn)程的默認(rèn)堆進(jìn)行對(duì)話。

            COM 的 IMalloc 分配程序(或 CoTaskMemAlloc / CoTaskMemFree):函數(shù)使用每個(gè)進(jìn)程的默認(rèn)堆。自動(dòng)化程序使用“組件對(duì)象模型 (COM)”的分配程序,而申請(qǐng)的程序使用每個(gè)進(jìn)程堆。

            C/C++ 運(yùn)行時(shí) (CRT) 分配程序:提供了 malloc() 和 free() 以及 new 和 delete 操作符。如 Microsoft Visual Basic 和 Java 等語(yǔ)言也提供了新的操作符并使用垃圾收集來(lái)代替堆。CRT 創(chuàng)建自己的私有堆,駐留在 Win32 堆的頂部。

            Windows NT 中,Win32 堆是 Windows NT 運(yùn)行時(shí)分配程序周?chē)谋印K?nbsp;API 轉(zhuǎn)發(fā)它們的請(qǐng)求給 NTDLL。

            Windows NT 運(yùn)行時(shí)分配程序提供 Windows NT 內(nèi)的核心堆分配程序。它由具有 128 個(gè)大小從 8 到 1,024 字節(jié)的空閑列表的前端分配程序組成。后端分配程序使用虛擬內(nèi)存來(lái)保留和提交頁(yè)。

            在圖表的底部是“虛擬內(nèi)存分配程序”,操作系統(tǒng)使用它來(lái)保留和提交頁(yè)。所有分配程序使用虛擬內(nèi)存進(jìn)行數(shù)據(jù)的存取。

            分配和釋放塊不就那么簡(jiǎn)單嗎?為何花費(fèi)這么長(zhǎng)時(shí)間?

            堆實(shí)現(xiàn)的注意事項(xiàng)
            傳統(tǒng)上,操作系統(tǒng)和運(yùn)行時(shí)庫(kù)是與堆的實(shí)現(xiàn)共存的。在一個(gè)進(jìn)程的開(kāi)始,操作系統(tǒng)創(chuàng)建一個(gè)默認(rèn)堆,叫做“進(jìn)程堆”。如果沒(méi)有其他堆可使用,則塊的分配使用“進(jìn)程堆”。語(yǔ)言運(yùn)行時(shí)也能在進(jìn)程內(nèi)創(chuàng)建單獨(dú)的堆。(例如,C 運(yùn)行時(shí)創(chuàng)建它自己的堆。)除這些專(zhuān)用的堆外,應(yīng)用程序或許多已載入的動(dòng)態(tài)鏈接庫(kù) (DLL) 之一可以創(chuàng)建和使用單獨(dú)的堆。Win32 提供一整套 API 來(lái)創(chuàng)建和使用私有堆。有關(guān)堆函數(shù)(英文)的詳盡指導(dǎo),請(qǐng)參見(jiàn) MSDN。

            當(dāng)應(yīng)用程序或 DLL 創(chuàng)建私有堆時(shí),這些堆存在于進(jìn)程空間,并且在進(jìn)程內(nèi)是可訪問(wèn)的。從給定堆分配的數(shù)據(jù)將在同一個(gè)堆上釋放。(不能從一個(gè)堆分配而在另一個(gè)堆釋放。)

            在所有虛擬內(nèi)存系統(tǒng)中,堆駐留在操作系統(tǒng)的“虛擬內(nèi)存管理器”的頂部。語(yǔ)言運(yùn)行時(shí)堆也駐留在虛擬內(nèi)存頂部。某些情況下,這些堆是操作系統(tǒng)堆中的層,而語(yǔ)言運(yùn)行時(shí)堆則通過(guò)大塊的分配來(lái)執(zhí)行自己的內(nèi)存管理。不使用操作系統(tǒng)堆,而使用虛擬內(nèi)存函數(shù)更利于堆的分配和塊的使用。

            典型的堆實(shí)現(xiàn)由前、后端分配程序組成。前端分配程序維持固定大小塊的空閑列表。對(duì)于一次分配調(diào)用,堆嘗試從前端列表找到一個(gè)自由塊。如果失敗,堆被迫從后端(保留和提交虛擬內(nèi)存)分配一個(gè)大塊來(lái)滿(mǎn)足請(qǐng)求。通用的實(shí)現(xiàn)有每塊分配的開(kāi)銷(xiāo),這將耗費(fèi)執(zhí)行周期,也減少了可使用的存儲(chǔ)空間。

            Knowledge Base 文章 Q10758,“用 calloc() 和 malloc() 管理內(nèi)存” (搜索文章編號(hào)), 包含了有關(guān)這些主題的更多背景知識(shí)。另外,有關(guān)堆實(shí)現(xiàn)和設(shè)計(jì)的詳細(xì)討論也可在下列著作中找到:“Dynamic Storage Allocation: A Survey and Critical Review”,作者 Paul R. Wilson、Mark S. Johnstone、Michael Neely 和 David Boles;“International Workshop on Memory Management”, 作者 Kinross, Scotland, UK, 1995 年 9 月(http://www.cs.utexas.edu/users/oops/papers.html)(英文)。

            Windows NT 的實(shí)現(xiàn)(Windows NT 版本 4.0 和更新版本) 使用了 127 個(gè)大小從 8 到 1,024 字節(jié)的 8 字節(jié)對(duì)齊塊空閑列表和一個(gè)“大塊”列表。“大塊”列表(空閑列表[0]) 保存大于 1,024 字節(jié)的塊。空閑列表容納了用雙向鏈表鏈接在一起的對(duì)象。默認(rèn)情況下,“進(jìn)程堆”執(zhí)行收集操作。(收集是將相鄰空閑塊合并成一個(gè)大塊的操作。)收集耗費(fèi)了額外的周期,但減少了堆塊的內(nèi)部碎片。

            單一全局鎖保護(hù)堆,防止多線程式的使用。(請(qǐng)參見(jiàn)“Server Performance and Scalability Killers”中的第一個(gè)注意事項(xiàng), George Reilly 所著,在 “MSDN Online Web Workshop”上(站點(diǎn):http://msdn.microsoft.com/workshop/server/iis/tencom.asp(英文)。)單一全局鎖本質(zhì)上是用來(lái)保護(hù)堆數(shù)據(jù)結(jié)構(gòu),防止跨多線程的隨機(jī)存取。若堆操作太頻繁,單一全局鎖會(huì)對(duì)性能有不利的影響。

            什么是常見(jiàn)的堆性能問(wèn)題?
            以下是您使用堆時(shí)會(huì)遇到的最常見(jiàn)問(wèn)題: 

            分配操作造成的速度減慢。光分配就耗費(fèi)很長(zhǎng)時(shí)間。最可能導(dǎo)致運(yùn)行速度減慢原因是空閑列表沒(méi)有塊,所以運(yùn)行時(shí)分配程序代碼會(huì)耗費(fèi)周期尋找較大的空閑塊,或從后端分配程序分配新塊。


            釋放操作造成的速度減慢。釋放操作耗費(fèi)較多周期,主要是啟用了收集操作。收集期間,每個(gè)釋放操作“查找”它的相鄰塊,取出它們并構(gòu)造成較大塊,然后再把此較大塊插入空閑列表。在查找期間,內(nèi)存可能會(huì)隨機(jī)碰到,從而導(dǎo)致高速緩存不能命中,性能降低。


            堆競(jìng)爭(zhēng)造成的速度減慢。當(dāng)兩個(gè)或多個(gè)線程同時(shí)訪問(wèn)數(shù)據(jù),而且一個(gè)線程繼續(xù)進(jìn)行之前必須等待另一個(gè)線程完成時(shí)就發(fā)生競(jìng)爭(zhēng)。競(jìng)爭(zhēng)總是導(dǎo)致麻煩;這也是目前多處理器系統(tǒng)遇到的最大問(wèn)題。當(dāng)大量使用內(nèi)存塊的應(yīng)用程序或 DLL 以多線程方式運(yùn)行(或運(yùn)行于多處理器系統(tǒng)上)時(shí)將導(dǎo)致速度減慢。單一鎖定的使用—常用的解決方案—意味著使用堆的所有操作是序列化的。當(dāng)?shù)却i定時(shí)序列化會(huì)引起線程切換上下文。可以想象交叉路口閃爍的紅燈處走走停停導(dǎo)致的速度減慢。 
            競(jìng)爭(zhēng)通常會(huì)導(dǎo)致線程和進(jìn)程的上下文切換。上下文切換的開(kāi)銷(xiāo)是很大的,但開(kāi)銷(xiāo)更大的是數(shù)據(jù)從處理器高速緩存中丟失,以及后來(lái)線程復(fù)活時(shí)的數(shù)據(jù)重建。

            堆破壞造成的速度減慢。造成堆破壞的原因是應(yīng)用程序?qū)Χ褖K的不正確使用。通常情形包括釋放已釋放的堆塊或使用已釋放的堆塊,以及塊的越界重寫(xiě)等明顯問(wèn)題。(破壞不在本文討論范圍之內(nèi)。有關(guān)內(nèi)存重寫(xiě)和泄漏等其他細(xì)節(jié),請(qǐng)參見(jiàn) Microsoft Visual C++(R) 調(diào)試文檔 。)


            頻繁的分配和重分配造成的速度減慢。這是使用腳本語(yǔ)言時(shí)非常普遍的現(xiàn)象。如字符串被反復(fù)分配,隨重分配增長(zhǎng)和釋放。不要這樣做,如果可能,盡量分配大字符串和使用緩沖區(qū)。另一種方法就是盡量少用連接操作。
            競(jìng)爭(zhēng)是在分配和釋放操作中導(dǎo)致速度減慢的問(wèn)題。理想情況下,希望使用沒(méi)有競(jìng)爭(zhēng)和快速分配/釋放的堆。可惜,現(xiàn)在還沒(méi)有這樣的通用堆,也許將來(lái)會(huì)有。

            在所有的服務(wù)器系統(tǒng)中(如 IIS、MSProxy、DatabaseStacks、網(wǎng)絡(luò)服務(wù)器、 Exchange 和其他), 堆鎖定實(shí)在是個(gè)大瓶頸。處理器數(shù)越多,競(jìng)爭(zhēng)就越會(huì)惡化。

            盡量減少堆的使用
            現(xiàn)在您明白使用堆時(shí)存在的問(wèn)題了,難道您不想擁有能解決這些問(wèn)題的超級(jí)魔棒嗎?我可希望有。但沒(méi)有魔法能使堆運(yùn)行加快—因此不要期望在產(chǎn)品出貨之前的最后一星期能夠大為改觀。如果提前規(guī)劃堆策略,情況將會(huì)大大好轉(zhuǎn)。調(diào)整使用堆的方法,減少對(duì)堆的操作是提高性能的良方。

            如何減少使用堆操作?通過(guò)利用數(shù)據(jù)結(jié)構(gòu)內(nèi)的位置可減少堆操作的次數(shù)。請(qǐng)考慮下列實(shí)例:

            struct ObjectA {
               // objectA 的數(shù)據(jù) 
            }

            struct ObjectB {
               // objectB 的數(shù)據(jù) 
            }

            // 同時(shí)使用 objectA 和 objectB

            //
            // 使用指針 
            //
            struct ObjectB {
               struct ObjectA * pObjA;
               // objectB 的數(shù)據(jù) 
            }

            //
            // 使用嵌入
            //
            struct ObjectB {
               struct ObjectA pObjA;
               // objectB 的數(shù)據(jù) 
            }

            //
            // 集合 – 在另一對(duì)象內(nèi)使用 objectA 和 objectB
            //

            struct ObjectX {
               struct ObjectA  objA;
               struct ObjectB  objB;
            }

            避免使用指針關(guān)聯(lián)兩個(gè)數(shù)據(jù)結(jié)構(gòu)。如果使用指針關(guān)聯(lián)兩個(gè)數(shù)據(jù)結(jié)構(gòu),前面實(shí)例中的對(duì)象 A 和 B 將被分別分配和釋放。這會(huì)增加額外開(kāi)銷(xiāo)—我們要避免這種做法。


            把帶指針的子對(duì)象嵌入父對(duì)象。當(dāng)對(duì)象中有指針時(shí),則意味著對(duì)象中有動(dòng)態(tài)元素(百分之八十)和沒(méi)有引用的新位置。嵌入增加了位置從而減少了進(jìn)一步分配/釋放的需求。這將提高應(yīng)用程序的性能。


            合并小對(duì)象形成大對(duì)象(聚合)。聚合減少分配和釋放的塊的數(shù)量。如果有幾個(gè)開(kāi)發(fā)者,各自開(kāi)發(fā)設(shè)計(jì)的不同部分,則最終會(huì)有許多小對(duì)象需要合并。集成的挑戰(zhàn)就是要找到正確的聚合邊界。


            內(nèi)聯(lián)緩沖區(qū)能夠滿(mǎn)足百分之八十的需要(aka 80-20 規(guī)則)。個(gè)別情況下,需要內(nèi)存緩沖區(qū)來(lái)保存字符串/二進(jìn)制數(shù)據(jù),但事先不知道總字節(jié)數(shù)。估計(jì)并內(nèi)聯(lián)一個(gè)大小能滿(mǎn)足百分之八十需要的緩沖區(qū)。對(duì)剩余的百分之二十,可以分配一個(gè)新的緩沖區(qū)和指向這個(gè)緩沖區(qū)的指針。這樣,就減少分配和釋放調(diào)用并增加數(shù)據(jù)的位置空間,從根本上提高代碼的性能。


            在塊中分配對(duì)象(塊化)。塊化是以組的方式一次分配多個(gè)對(duì)象的方法。如果對(duì)列表的項(xiàng)連續(xù)跟蹤,例如對(duì)一個(gè) {名稱(chēng),值} 對(duì)的列表,有兩種選擇:選擇一是為每一個(gè)“名稱(chēng)-值”對(duì)分配一個(gè)節(jié)點(diǎn);選擇二是分配一個(gè)能容納(如五個(gè))“名稱(chēng)-值”對(duì)的結(jié)構(gòu)。例如,一般情況下,如果存儲(chǔ)四對(duì),就可減少節(jié)點(diǎn)的數(shù)量,如果需要額外的空間數(shù)量,則使用附加的鏈表指針。 
            塊化是友好的處理器高速緩存,特別是對(duì)于 L1-高速緩存,因?yàn)樗峁┝嗽黾拥奈恢?nbsp;—不用說(shuō)對(duì)于塊分配,很多數(shù)據(jù)塊會(huì)在同一個(gè)虛擬頁(yè)中。

            正確使用 _amblksiz。C 運(yùn)行時(shí) (CRT) 有它的自定義前端分配程序,該分配程序從后端(Win32 堆)分配大小為 _amblksiz 的塊。將 _amblksiz 設(shè)置為較高的值能潛在地減少對(duì)后端的調(diào)用次數(shù)。這只對(duì)廣泛使用 CRT 的程序適用。
            使用上述技術(shù)將獲得的好處會(huì)因?qū)ο箢?lèi)型、大小及工作量而有所不同。但總能在性能和可升縮性方面有所收獲。另一方面,代碼會(huì)有點(diǎn)特殊,但如果經(jīng)過(guò)深思熟慮,代碼還是很容易管理的。

            其他提高性能的技術(shù)
            下面是一些提高速度的技術(shù): 

            使用 Windows NT5 堆 
            由于幾個(gè)同事的努力和辛勤工作,1998 年初 Microsoft Windows(R) 2000 中有了幾個(gè)重大改進(jìn):

            改進(jìn)了堆代碼內(nèi)的鎖定。堆代碼對(duì)每堆一個(gè)鎖。全局鎖保護(hù)堆數(shù)據(jù)結(jié)構(gòu),防止多線程式的使用。但不幸的是,在高通信量的情況下,堆仍受困于全局鎖,導(dǎo)致高競(jìng)爭(zhēng)和低性能。Windows 2000 中,鎖內(nèi)代碼的臨界區(qū)將競(jìng)爭(zhēng)的可能性減到最小,從而提高了可伸縮性。


            使用 “Lookaside”列表。堆數(shù)據(jù)結(jié)構(gòu)對(duì)塊的所有空閑項(xiàng)使用了大小在 8 到 1,024 字節(jié)(以 8-字節(jié)遞增)的快速高速緩存。快速高速緩存最初保護(hù)在全局鎖內(nèi)。現(xiàn)在,使用 lookaside 列表來(lái)訪問(wèn)這些快速高速緩存空閑列表。這些列表不要求鎖定,而是使用 64 位的互鎖操作,因此提高了性能。


            內(nèi)部數(shù)據(jù)結(jié)構(gòu)算法也得到改進(jìn)。
            這些改進(jìn)避免了對(duì)分配高速緩存的需求,但不排除其他的優(yōu)化。使用 Windows NT5 堆評(píng)估您的代碼;它對(duì)小于 1,024 字節(jié) (1 KB) 的塊(來(lái)自前端分配程序的塊)是最佳的。GlobalAlloc() 和 LocalAlloc() 建立在同一堆上,是存取每個(gè)進(jìn)程堆的通用機(jī)制。如果希望獲得高的局部性能,則使用 Heap(R) API 來(lái)存取每個(gè)進(jìn)程堆,或?yàn)榉峙洳僮鲃?chuàng)建自己的堆。如果需要對(duì)大塊操作,也可以直接使用 VirtualAlloc() / VirtualFree() 操作。

            上述改進(jìn)已在 Windows 2000 beta 2 和 Windows NT 4.0 SP4 中使用。改進(jìn)后,堆鎖的競(jìng)爭(zhēng)率顯著降低。這使所有 Win32 堆的直接用戶(hù)受益。CRT 堆建立于 Win32 堆的頂部,但它使用自己的小塊堆,因而不能從 Windows NT 改進(jìn)中受益。(Visual C++ 版本 6.0 也有改進(jìn)的堆分配程序。)

            使用分配高速緩存 
            分配高速緩存允許高速緩存分配的塊,以便將來(lái)重用。這能夠減少對(duì)進(jìn)程堆(或全局堆)的分配/釋放調(diào)用的次數(shù),也允許最大限度的重用曾經(jīng)分配的塊。另外,分配高速緩存允許收集統(tǒng)計(jì)信息,以便較好地理解對(duì)象在較高層次上的使用。

            典型地,自定義堆分配程序在進(jìn)程堆的頂部實(shí)現(xiàn)。自定義堆分配程序與系統(tǒng)堆的行為很相似。主要的差別是它在進(jìn)程堆的頂部為分配的對(duì)象提供高速緩存。高速緩存設(shè)計(jì)成一套固定大小(如 32 字節(jié)、64 字節(jié)、128 字節(jié)等)。這一個(gè)很好的策略,但這種自定義堆分配程序丟失與分配和釋放的對(duì)象相關(guān)的“語(yǔ)義信息”。 

            與自定義堆分配程序相反,“分配高速緩存”作為每類(lèi)分配高速緩存來(lái)實(shí)現(xiàn)。除能夠提供自定義堆分配程序的所有好處之外,它們還能夠保留大量語(yǔ)義信息。每個(gè)分配高速緩存處理程序與一個(gè)目標(biāo)二進(jìn)制對(duì)象關(guān)聯(lián)。它能夠使用一套參數(shù)進(jìn)行初始化,這些參數(shù)表示并發(fā)級(jí)別、對(duì)象大小和保持在空閑列表中的元素的數(shù)量等。分配高速緩存處理程序?qū)ο缶S持自己的私有空閑實(shí)體池(不超過(guò)指定的閥值)并使用私有保護(hù)鎖。合在一起,分配高速緩存和私有鎖減少了與主系統(tǒng)堆的通信量,因而提供了增加的并發(fā)、最大限度的重用和較高的可伸縮性。

            需要使用清理程序來(lái)定期檢查所有分配高速緩存處理程序的活動(dòng)情況并回收未用的資源。如果發(fā)現(xiàn)沒(méi)有活動(dòng),將釋放分配對(duì)象的池,從而提高性能。

            可以審核每個(gè)分配/釋放活動(dòng)。第一級(jí)信息包括對(duì)象、分配和釋放調(diào)用的總數(shù)。通過(guò)查看它們的統(tǒng)計(jì)信息可以得出各個(gè)對(duì)象之間的語(yǔ)義關(guān)系。利用以上介紹的許多技術(shù)之一,這種關(guān)系可以用來(lái)減少內(nèi)存分配。

            分配高速緩存也起到了調(diào)試助手的作用,幫助您跟蹤沒(méi)有完全清除的對(duì)象數(shù)量。通過(guò)查看動(dòng)態(tài)堆棧返回蹤跡和除沒(méi)有清除的對(duì)象之外的簽名,甚至能夠找到確切的失敗的調(diào)用者。

            MP 堆 
            MP 堆是對(duì)多處理器友好的分布式分配的程序包,在 Win32 SDK(Windows NT 4.0 和更新版本)中可以得到。最初由 JVert 實(shí)現(xiàn),此處堆抽象建立在 Win32 堆程序包的頂部。MP 堆創(chuàng)建多個(gè) Win32 堆,并試圖將分配調(diào)用分布到不同堆,以減少在所有單一鎖上的競(jìng)爭(zhēng)。

            本程序包是好的步驟 —一種改進(jìn)的 MP-友好的自定義堆分配程序。但是,它不提供語(yǔ)義信息和缺乏統(tǒng)計(jì)功能。通常將 MP 堆作為 SDK 庫(kù)來(lái)使用。如果使用這個(gè) SDK 創(chuàng)建可重用組件,您將大大受益。但是,如果在每個(gè) DLL 中建立這個(gè) SDK 庫(kù),將增加工作設(shè)置。

            重新思考算法和數(shù)據(jù)結(jié)構(gòu) 
            要在多處理器機(jī)器上伸縮,則算法、實(shí)現(xiàn)、數(shù)據(jù)結(jié)構(gòu)和硬件必須動(dòng)態(tài)伸縮。請(qǐng)看最經(jīng)常分配和釋放的數(shù)據(jù)結(jié)構(gòu)。試問(wèn),“我能用不同的數(shù)據(jù)結(jié)構(gòu)完成此工作嗎?”例如,如果在應(yīng)用程序初始化時(shí)加載了只讀項(xiàng)的列表,這個(gè)列表不必是線性鏈接的列表。如果是動(dòng)態(tài)分配的數(shù)組就非常好。動(dòng)態(tài)分配的數(shù)組將減少內(nèi)存中的堆塊和碎片,從而增強(qiáng)性能。

            減少需要的小對(duì)象的數(shù)量減少堆分配程序的負(fù)載。例如,我們?cè)诜?wù)器的關(guān)鍵處理路徑上使用五個(gè)不同的對(duì)象,每個(gè)對(duì)象單獨(dú)分配和釋放。一起高速緩存這些對(duì)象,把堆調(diào)用從五個(gè)減少到一個(gè),顯著減少了堆的負(fù)載,特別當(dāng)每秒鐘處理 1,000 個(gè)以上的請(qǐng)求時(shí)。

            如果大量使用“Automation”結(jié)構(gòu),請(qǐng)考慮從主線代碼中刪除“Automation BSTR”,或至少避免重復(fù)的 BSTR 操作。(BSTR 連接導(dǎo)致過(guò)多的重分配和分配/釋放操作。)

            摘要
            對(duì)所有平臺(tái)往往都存在堆實(shí)現(xiàn),因此有巨大的開(kāi)銷(xiāo)。每個(gè)單獨(dú)代碼都有特定的要求,但設(shè)計(jì)能采用本文討論的基本理論來(lái)減少堆之間的相互作用。 

            評(píng)價(jià)您的代碼中堆的使用。


            改進(jìn)您的代碼,以使用較少的堆調(diào)用:分析關(guān)鍵路徑和固定數(shù)據(jù)結(jié)構(gòu)。


            在實(shí)現(xiàn)自定義的包裝程序之前使用量化堆調(diào)用成本的方法。


            如果對(duì)性能不滿(mǎn)意,請(qǐng)要求 OS 組改進(jìn)堆。更多這類(lèi)請(qǐng)求意味著對(duì)改進(jìn)堆的更多關(guān)注。


            要求 C 運(yùn)行時(shí)組針對(duì) OS 所提供的堆制作小巧的分配包裝程序。隨著 OS 堆的改進(jìn),C 運(yùn)行時(shí)堆調(diào)用的成本將減小。


            操作系統(tǒng)(Windows NT 家族)正在不斷改進(jìn)堆。請(qǐng)隨時(shí)關(guān)注和利用這些改進(jìn)。
            Murali Krishnan 是 Internet Information Server (IIS) 組的首席軟件設(shè)計(jì)工程師。從 1.0 版本開(kāi)始他就設(shè)計(jì) IIS,并成功發(fā)行了 1.0 版本到 4.0 版本。Murali 組織并領(lǐng)導(dǎo) IIS 性能組三年 (1995-1998), 從一開(kāi)始就影響 IIS 性能。他擁有威斯康星州 Madison 大學(xué)的 M.S.和印度 Anna 大學(xué)的 B.S.。工作之外,他喜歡閱讀、打排球和家庭烹飪。



            http://community.csdn.net/Expert/FAQ/FAQ_Index.asp?id=172835
            我在學(xué)習(xí)對(duì)象的生存方式的時(shí)候見(jiàn)到一種是在堆棧(stack)之中,如下  
            CObject  object;  
            還有一種是在堆(heap)中  如下  
            CObject*  pobject=new  CObject();  
             
            請(qǐng)問(wèn)  
            (1)這兩種方式有什么區(qū)別?  
            (2)堆棧與堆有什么區(qū)別??  
             
             
            ---------------------------------------------------------------  
             
            1)  about  stack,  system  will  allocate  memory  to  the  instance  of  object  automatically,  and  to  the
             heap,  you  must  allocate  memory  to  the  instance  of  object  with  new  or  malloc  manually.  
            2)  when  function  ends,  system  will  automatically  free  the  memory  area  of  stack,  but  to  the 
            heap,  you  must  free  the  memory  area  manually  with  free  or  delete,  else  it  will  result  in  memory
            leak.  
            3)棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。  
            4)堆上分配的內(nèi)存可以有我們自己決定,使用非常靈活。  

            posted @ 2008-09-09 19:00 深邃者 閱讀(140) | 評(píng)論 (0)編輯 收藏

            Ansi、Unicode、UTF8字符串之間的轉(zhuǎn)換和寫(xiě)入文本文件

            轉(zhuǎn)載請(qǐng)注明出處http://www.shnenglu.com/greatws/archive/2008/08/31/60546.html

            最近有人問(wèn)我關(guān)于這個(gè)的問(wèn)題,就此寫(xiě)一篇blog

            Ansi字符串我們最熟悉,英文占一個(gè)字節(jié),漢字2個(gè)字節(jié),以一個(gè)\0結(jié)尾,常用于txt文本文件
            Unicode字符串,每個(gè)字符(漢字、英文字母)都占2個(gè)字節(jié),以2個(gè)連續(xù)的\0結(jié)尾,NT操作系統(tǒng)內(nèi)核用的是這種字符串,常被定義為typedef unsigned short wchar_t;所以我們有時(shí)常會(huì)見(jiàn)到什么char*無(wú)法轉(zhuǎn)換為unsigned short*之類(lèi)的錯(cuò)誤,其實(shí)就是unicode
            UTF8是Unicode一種壓縮形式,英文A在unicode中表示為0x0041,老外覺(jué)得這種存儲(chǔ)方式太浪費(fèi),因?yàn)槔速M(fèi)了50%的空間,于是就把英文壓縮成1個(gè)字節(jié),成了utf8編碼,但是漢字在utf8中占3個(gè)字節(jié),顯然用做中文不如ansi合算,這就是中國(guó)的網(wǎng)頁(yè)用作ansi編碼而老外的網(wǎng)頁(yè)常用utf8的原因。
            UTF8在還游戲里運(yùn)用的很廣泛,比如WOW的lua腳本等

            下面來(lái)說(shuō)一下轉(zhuǎn)換,主要用代碼來(lái)說(shuō)明吧
            寫(xiě)文件我用了CFile類(lèi),其實(shí)用FILE*之類(lèi)的也是一樣,寫(xiě)文件和字符串什么類(lèi)別沒(méi)有關(guān)系,硬件只關(guān)心數(shù)據(jù)和長(zhǎng)度

            Ansi轉(zhuǎn)Unicode
            介紹2種方法


            void CConvertDlg::OnBnClickedButtonAnsiToUnicode()
            {
                
            // ansi to unicode
                char* szAnsi = "abcd1234你我他";
                
            //預(yù)轉(zhuǎn)換,得到所需空間的大小
                int wcsLen = ::MultiByteToWideChar(CP_ACP, NULL, szAnsi, strlen(szAnsi), NULL, 0);
                
            //分配空間要給'\0'留個(gè)空間,MultiByteToWideChar不會(huì)給'\0'空間
                wchar_t* wszString = new wchar_t[wcsLen + 1];
                
            //轉(zhuǎn)換
                ::MultiByteToWideChar(CP_ACP, NULL, szAnsi, strlen(szAnsi), wszString, wcsLen);
                
            //最后加上'\0'
                wszString[wcsLen] = '\0';
                
            //unicode版的MessageBox API
                ::MessageBoxW(GetSafeHwnd(), wszString, wszString, MB_OK);

                
            //接下來(lái)寫(xiě)入文本
                
            //寫(xiě)文本文件,頭2個(gè)字節(jié)0xfeff,低位0xff寫(xiě)在前
                CFile cFile;
                cFile.Open(_T(
            "1.txt"), CFile::modeWrite | CFile::modeCreate);
                
            //文件開(kāi)頭
                cFile.SeekToBegin();
                cFile.Write(
            "\xff\xfe"2);
                
            //寫(xiě)入內(nèi)容
                cFile.Write(wszString, wcsLen * sizeof(wchar_t));
                cFile.Flush();
                cFile.Close();
                delete[] wszString;
                wszString 
            =NULL;


                
            //方法2
                
            //設(shè)置當(dāng)前地域信息,不設(shè)置的話,使用這種方法,中文不會(huì)正確顯示
                
            //需要#include<locale.h>
                setlocale(LC_CTYPE, "chs"); 
                wchar_t wcsStr[
            100];
                
            //注意下面是大寫(xiě)S,在unicode中,代表后面是ansi字符串
                
            //swprintf是sprintf的unicode版本
                
            //格式的前面要加大寫(xiě)L,代表是unicode
                swprintf(wcsStr, L"%S", szAnsi);
                ::MessageBoxW(GetSafeHwnd(), wcsStr, wcsStr, MB_OK);

            }


            Unicode轉(zhuǎn)Ansi
            也是2種方法

            void CConvertDlg::OnBnClickedButtonUnicodeToAnsi()
            {
                
            // unicode to ansi
                wchar_t* wszString = L"abcd1234你我他";
                
            //預(yù)轉(zhuǎn)換,得到所需空間的大小,這次用的函數(shù)和上面名字相反
                int ansiLen = ::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), NULL, 0, NULL, NULL);
                
            //同上,分配空間要給'\0'留個(gè)空間
                char* szAnsi = new char[ansiLen + 1];
                
            //轉(zhuǎn)換
                
            //unicode版對(duì)應(yīng)的strlen是wcslen
                ::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), szAnsi, ansiLen, NULL, NULL);
                
            //最后加上'\0'
                szAnsi[ansiLen] = '\0';
                
            //Ansi版的MessageBox API
                ::MessageBoxA(GetSafeHwnd(), szAnsi, szAnsi, MB_OK);

                
            //接下來(lái)寫(xiě)入文本
                
            //寫(xiě)文本文件,ANSI文件沒(méi)有BOM
                CFile cFile;
                cFile.Open(_T(
            "1.txt"), CFile::modeWrite | CFile::modeCreate);
                
            //文件開(kāi)頭
                cFile.SeekToBegin();
                
            //寫(xiě)入內(nèi)容
                cFile.Write(szAnsi, ansiLen * sizeof(char));
                cFile.Flush();
                cFile.Close();
                delete[] szAnsi;
                szAnsi 
            =NULL;


                
            //方法2
                
            //和上面一樣有另一種方法
                setlocale(LC_CTYPE, "chs"); 
                
            char szStr[100];
                
            //注意下面是大寫(xiě),在ansi中,代表后面是unicode字符串
                
            //sprintf
                sprintf(szStr, "%S", wszString);
                ::MessageBoxA(GetSafeHwnd(), szStr, szStr, MB_OK);
            }


            Unicode轉(zhuǎn)UTF8

            void CConvertDlg::OnBnClickedButtonUnicodeToU8()
            {
                
            // unicode to UTF8
                wchar_t* wszString = L"abcd1234你我他";
                
            //預(yù)轉(zhuǎn)換,得到所需空間的大小,這次用的函數(shù)和上面名字相反
                int u8Len = ::WideCharToMultiByte(CP_UTF8, NULL, wszString, wcslen(wszString), NULL, 0, NULL, NULL);
                
            //同上,分配空間要給'\0'留個(gè)空間
                
            //UTF8雖然是Unicode的壓縮形式,但也是多字節(jié)字符串,所以可以以char的形式保存
                char* szU8 = new char[u8Len + 1];
                
            //轉(zhuǎn)換
                
            //unicode版對(duì)應(yīng)的strlen是wcslen
                ::WideCharToMultiByte(CP_UTF8, NULL, wszString, wcslen(wszString), szU8, u8Len, NULL, NULL);
                
            //最后加上'\0'
                szU8[u8Len] = '\0';
                
            //MessageBox不支持UTF8,所以只能寫(xiě)文件

                
            //接下來(lái)寫(xiě)入文本
                
            //寫(xiě)文本文件,UTF8的BOM是0xbfbbef
                CFile cFile;
                cFile.Open(_T(
            "1.txt"), CFile::modeWrite | CFile::modeCreate);
                
            //文件開(kāi)頭
                cFile.SeekToBegin();
                
            //寫(xiě)B(tài)OM,同樣低位寫(xiě)在前
                cFile.Write("\xef\xbb\xbf"3);
                
            //寫(xiě)入內(nèi)容
                cFile.Write(szU8, u8Len * sizeof(char));
                cFile.Flush();
                cFile.Close();
                delete[] szU8;
                szU8 
            =NULL;

            }

            UTF8轉(zhuǎn)UNICODE

            void CConvertDlg::OnBnClickedButtonU8ToUnicode()
            {
                
            //UTF8 to Unicode
                
            //由于中文直接復(fù)制過(guò)來(lái)會(huì)成亂碼,編譯器有時(shí)會(huì)報(bào)錯(cuò),故采用16進(jìn)制形式
                char* szU8 = "abcd1234\xe4\xbd\xa0\xe6\x88\x91\xe4\xbb\x96\x00";
                
            //預(yù)轉(zhuǎn)換,得到所需空間的大小
                int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), NULL, 0);
                
            //分配空間要給'\0'留個(gè)空間,MultiByteToWideChar不會(huì)給'\0'空間
                wchar_t* wszString = new wchar_t[wcsLen + 1];
                
            //轉(zhuǎn)換
                ::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), wszString, wcsLen);
                
            //最后加上'\0'
                wszString[wcsLen] = '\0';
                
            //unicode版的MessageBox API
                ::MessageBoxW(GetSafeHwnd(), wszString, wszString, MB_OK);

                
            //寫(xiě)文本同ansi to unicode
            }



            Ansi轉(zhuǎn)換utf8和utf8轉(zhuǎn)換Ansi就是上面2個(gè)的結(jié)合,把unicode作為中間量,進(jìn)行2次轉(zhuǎn)換即可

            posted @ 2008-09-04 16:27 深邃者 閱讀(383) | 評(píng)論 (0)編輯 收藏

            讀寫(xiě)ini文件

                    ini文件(即Initialization file),這種類(lèi)型的文件中通常存放的是一個(gè)程序的初始化信息。ini文件由若干個(gè)節(jié)(Section)組成,每個(gè)Section由若干鍵(Key)組成,每個(gè)Key可以賦相應(yīng)的值。讀寫(xiě)ini文件實(shí)際上就是讀寫(xiě)某個(gè)的Section中相應(yīng)的Key的值,而這只要借助幾個(gè)函數(shù)即可完成。
            一、向ini文件中寫(xiě)入信息的函數(shù)
            1. 把信息寫(xiě)入系統(tǒng)的win.ini文件

            BOOL WriteProfileString(
                 LPCTSTR lpAppName, // 節(jié)的名字,是一個(gè)以0結(jié)束的字符串
                 LPCTSTR lpKeyName, // 鍵的名字,是一個(gè)以0結(jié)束的字符串。若為NULL,則刪除整個(gè)節(jié)
                 LPCTSTR lpString      // 鍵的值,是一個(gè)以0結(jié)束的字符串。若為NULL,則刪除對(duì)應(yīng)的鍵
            )


            2. 把信息寫(xiě)入自己定義的.ini文件
            BOOL WritePrivateProfileString(
                 LPCTSTR lpAppName,     // 同上
                 LPCTSTR lpKeyName,     // 同上
                 LPCTSTR lpString,      // 同上
                 LPCTSTR lpFileName     // 要寫(xiě)入的文件的文件名。若該ini文件與程序在同一個(gè)目錄下,也可使用相對(duì)
                       //路徑,否則需要給出絕度路徑。
            )

            如:
            ::WriteProfileString("Test","id","xym");  
            //在win.ini中創(chuàng)建一個(gè)Test節(jié),并在該節(jié)中創(chuàng)建一個(gè)鍵id,其值為xym

            ::WritePrivateProfileString("Test","id","xym","d:\\vc\\Ex1\\ex1.ini");
            //在Ex1目錄下的ex1.ini中創(chuàng)建一個(gè)Test節(jié),并在該節(jié)中創(chuàng)建一個(gè)鍵id,其值為xym

            //若Ex1.ini文件與讀寫(xiě)該文件的程序在同一個(gè)目錄下,則上面語(yǔ)句也可寫(xiě)為:
            ::WritePrivateProfileString("Test","id","xym",".\\ex1.ini");

            需要注意的是,C系列的語(yǔ)言中,轉(zhuǎn)義字符'\\'表示反斜線'\'。另外,當(dāng)使用相對(duì)路徑時(shí),\\前的.號(hào)不能丟掉了。

            二、從ini文件中讀取數(shù)據(jù)的函數(shù)
            1、從系統(tǒng)的win.ini文件中讀取信息
            (1) 讀取字符串

            DWORD GetProfileString(
                 LPCTSTR lpAppName,           // 節(jié)名
                 LPCTSTR lpKeyName,           // 鍵名,讀取該鍵的值
                 LPCTSTR lpDefault,           // 若指定的鍵不存在,該值作為讀取的默認(rèn)值
                 LPTSTR lpReturnedString,     // 一個(gè)指向緩沖區(qū)的指針,接收讀取的字符串
                 DWORD nSize                  // 指定lpReturnedString指向的緩沖區(qū)的大小
            )

            如:
            CString str;
            ::GetProfileString("Test","id","Error",str.GetBuffer(20),20);

            (2) 讀取整數(shù)
            UINT GetProfileInt(
                 LPCTSTR lpAppName,     // 同上
                 LPCTSTR lpKeyName,     // 同上
                 INT nDefault           // 若指定的鍵名不存在,該值作為讀取的默認(rèn)值
            )

            如使用以下語(yǔ)句寫(xiě)入了年齡信息:
            ::WriteProfileString("Test","age","25");  
            //在win.ini中創(chuàng)建一個(gè)Test節(jié),并在該節(jié)中創(chuàng)建一個(gè)鍵age,其值為25

            則可用以下語(yǔ)句讀取age鍵的值:
            int age;
            age=::GetProfileInt("Test","age",0);

            2、從自己的ini文件中讀取信息
            (1) 讀取字符串
            DWORD GetPrivateProfileString(
                 LPCTSTR lpAppName,           // 同1(1)
                 LPCTSTR lpKeyName,           // 同1(1)
                 LPCTSTR lpDefault,           // 同1(1)
                 LPTSTR lpReturnedString,     // 同1(1)
                 DWORD nSize,                 // 同1(1)
                 LPCTSTR lpFileName           // 讀取信息的文件名。若該ini文件與程序在同一個(gè)目錄下,也可使用相      
                       //對(duì)路徑,否則需要給出絕度路徑。
            )

            如:
            CString str;
            ::GetPrivateProfileString("Test","id","Error",str.GetBuffer(20),20,".\\ex1.ini");
            或:
            ::GetPrivateProfileString("Test","id","Error",str.GetBuffer(20),20,"d:\\vc\\Ex1\\ex1.ini");

            (2) 讀取整數(shù)

            UINT GetPrivateProfileInt(
                 LPCTSTR lpAppName,     // 同上
                 LPCTSTR lpKeyName,     // 同上
                 INT nDefault,          // 若指定的鍵名不存在,該值作為讀取的默認(rèn)值
                 LPCTSTR lpFileName     // 同上
            )

            如使用以下語(yǔ)句寫(xiě)入了年齡信息:
            ::WritePrivateProfileString("Test","age","25",".\\ex1.ini");  
            //在ex1.ini中創(chuàng)建一個(gè)Test節(jié),并在該節(jié)中創(chuàng)建一個(gè)鍵age,其值為25

            則可用以下語(yǔ)句讀取age鍵的值:
            int age;
            age=::GetPrivateProfileInt("Test","age",0,".\\ex1.ini");

            三、 刪除鍵值或節(jié)

                  回顧一下WriteProfileString函數(shù)的說(shuō)明
            BOOL WriteProfileString(
                 LPCTSTR lpAppName, // 節(jié)的名字,是一個(gè)以0結(jié)束的字符串
                 LPCTSTR lpKeyName, // 鍵的名字,是一個(gè)以0結(jié)束的字符串。若為NULL,則刪除整個(gè)節(jié)
                 LPCTSTR lpString      // 鍵的值,是一個(gè)以0結(jié)束的字符串。若為NULL,則刪除對(duì)應(yīng)的鍵
            )

                  由此可見(jiàn),要?jiǎng)h除某個(gè)節(jié),只需要將WriteProfileString第二個(gè)參數(shù)設(shè)為NULL即可。而要?jiǎng)h除某個(gè)鍵,則只需要將該函數(shù)的第三個(gè)參數(shù)設(shè)為NULL即可。這是刪除系統(tǒng)的win.ini中的節(jié)或鍵,類(lèi)似的,要?jiǎng)h除自己定義的ini文件中的節(jié)或鍵,也可做相同的操作。
                  如:
            ::WriteProfileString("Test",NULL,NULL);     //刪除win.ini中的Test節(jié)
            ::WriteProfileString("Test","id",NULL);     //刪除win.ini中的id鍵

            ::WritePrivateProfileString("Test",NULL,NULL,".\\ex1.ini");     //刪除ex1.ini中的Test節(jié)
            ::WritePrivateProfileString("Test","id",NULL,".\\ex1.ini");     //刪除ex1.ini中的id鍵

            四、如何判斷一個(gè)ini文件中有多少個(gè)節(jié)
                  要判斷一個(gè)ini文件中有多少個(gè)節(jié),最簡(jiǎn)單的辦法就是將所有的節(jié)名都找出來(lái),然后統(tǒng)計(jì)節(jié)名的個(gè)數(shù)。而要將所有的節(jié)名找出來(lái),使用GetPrivateProfileSectionNames函數(shù)就可以了,其原型如下:
            DWORD GetPrivateProfileSectionNames(
                 LPTSTR lpszReturnBuffer,     // 指向一個(gè)緩沖區(qū),用來(lái)保存返回的所有節(jié)名
                 DWORD nSize,                 // 參數(shù)lpszReturnBuffer的大小
                 LPCTSTR lpFileName           // 文件名,若該ini文件與程序在同一個(gè)目錄下,

                                                           //也可使用相對(duì)路徑,否則需要給出絕度路徑
            )

            下面的是用來(lái)統(tǒng)計(jì)一個(gè)ini文件中共有多少個(gè)節(jié)的函數(shù),當(dāng)然,如果需要同時(shí)找到每個(gè)節(jié)中的各個(gè)鍵及其值,根據(jù)找到節(jié)名就可以很容易的得到了。


            /*統(tǒng)計(jì)共有多少個(gè)節(jié)
            節(jié)名的分離方法:若chSectionNames數(shù)組的第一字符是'\0'字符,則表明
            有0個(gè)節(jié)。否則,從chSectionNames數(shù)組的第一個(gè)字符開(kāi)始,順序往后找,
            直到找到一個(gè)'\0'字符,若該字符的后繼字符不是 '\0'字符,則表明前
            面的字符組成一個(gè)節(jié)名。若連續(xù)找到兩個(gè)'\0'字符,則統(tǒng)計(jì)結(jié)束*/


            int CTestDlg::CalcCount(void)
            {
            TCHAR      chSectionNames[2048]={0};      //所有節(jié)名組成的字符數(shù)組
            char * pSectionName; //保存找到的某個(gè)節(jié)名字符串的首地址
            int i;      //i指向數(shù)組chSectionNames的某個(gè)位置,從0開(kāi)始,順序后移
            int j=0;     //j用來(lái)保存下一個(gè)節(jié)名字符串的首地址相對(duì)于當(dāng)前i的位置偏移量
            int count=0;     //統(tǒng)計(jì)節(jié)的個(gè)數(shù)

            //CString name;
            //char id[20];
            ::GetPrivateProfileSectionNames(chSectionNames,2048,".\\ex1.ini");   
            for(i=0;i<2048;i++,j++)
            {
                 if(chSectionNames[0]=='\0')
                  break;      //如果第一個(gè)字符就是0,則說(shuō)明ini中一個(gè)節(jié)也沒(méi)有
                 if(chSectionNames[i]=='\0')
                 {
                  pSectionName=&chSectionNames[i-j]; //找到一個(gè)0,則說(shuō)明從這個(gè)字符往前,減掉j個(gè)偏移量,
                       //就是一個(gè)節(jié)名的首地址

                  j=-1;        //找到一個(gè)節(jié)名后,j的值要還原,以統(tǒng)計(jì)下一個(gè)節(jié)名地址的偏移量
                       //賦成-1是因?yàn)楣?jié)名字符串的最后一個(gè)字符0是終止符,不能作為節(jié)名

                       //的一部分
                  /*::GetPrivateProfileString(pSectionName,"id","Error",id,20,".\\ex1.ini");
                  name.Format("%s",id);*/   
                  //在獲取節(jié)名的時(shí)候可以獲取該節(jié)中鍵的值,前提是我們知道該節(jié)中有哪些鍵。
               
                  AfxMessageBox(pSectionName);     //把找到的顯示出來(lái)

                  if(chSectionNames[i+1]==0)
                  {
                    break;     //當(dāng)兩個(gè)相鄰的字符都是0時(shí),則所有的節(jié)名都已找到,循環(huán)終止
                  }
                 }   
              
            }

            return count;
            }

            posted @ 2008-09-02 15:19 深邃者 閱讀(226) | 評(píng)論 (0)編輯 收藏

            Window API函數(shù)大全(2)

            10. API之硬件與系統(tǒng)函數(shù)
            ActivateKeyboardLayout 激活一個(gè)新的鍵盤(pán)布局。鍵盤(pán)布局定義了按鍵在一種物理性鍵盤(pán)上的位置與含義
            Beep 用于生成簡(jiǎn)單的聲音
            CharToOem 將一個(gè)字串從ANSI字符集轉(zhuǎn)換到OEM字符集
            ClipCursor 將指針限制到指定區(qū)域
            ConvertDefaultLocale 將一個(gè)特殊的地方標(biāo)識(shí)符轉(zhuǎn)換成真實(shí)的地方ID
            CreateCaret 根據(jù)指定的信息創(chuàng)建一個(gè)插入符(光標(biāo)),并將它選定為指定窗口的默認(rèn)插入符
            DestroyCaret 清除(破壞)一個(gè)插入符
            EnumCalendarInfo 枚舉在指定“地方”環(huán)境中可用的日歷信息
            EnumDateFormats 列舉指定的“當(dāng)?shù)?#8221;設(shè)置中可用的長(zhǎng)、短日期格式
            EnumSystemCodePages 枚舉系統(tǒng)中已安裝或支持的代碼頁(yè)
            EnumSystemLocales 枚舉系統(tǒng)已經(jīng)安裝或提供支持的“地方”設(shè)置
            EnumTimeFormats 枚舉一個(gè)指定的地方適用的時(shí)間格式
            ExitWindowsEx 退出windows,并用特定的選項(xiàng)重新啟動(dòng)
            ExpandEnvironmentStrings 擴(kuò)充環(huán)境字串
            FreeEnvironmentStrings 翻譯指定的環(huán)境字串塊
            GetACP 判斷目前正在生效的ANSI代碼頁(yè)
            GetAsyncKeyState 判斷函數(shù)調(diào)用時(shí)指定虛擬鍵的狀態(tài)
            GetCaretBlinkTime 判斷插入符光標(biāo)的閃爍頻率
            GetCaretPos 判斷插入符的當(dāng)前位置
            GetClipCursor 取得一個(gè)矩形,用于描述目前為鼠標(biāo)指針規(guī)定的剪切區(qū)域
            GetCommandLine 獲得指向當(dāng)前命令行緩沖區(qū)的一個(gè)指針
            GetComputerName 取得這臺(tái)計(jì)算機(jī)的名稱(chēng)
            GetCPInfo 取得與指定代碼頁(yè)有關(guān)的信息
            GetCurrencyFormat 針對(duì)指定的“地方”設(shè)置,根據(jù)貨幣格式格式化一個(gè)數(shù)字
            GetCursor 獲取目前選擇的鼠標(biāo)指針的句柄
            GetCursorPos 獲取鼠標(biāo)指針的當(dāng)前位置
            GetDateFormat 針對(duì)指定的“當(dāng)?shù)?#8221;格式,對(duì)一個(gè)系統(tǒng)日期進(jìn)行格式化
            GetDoubleClickTime 判斷連續(xù)兩次鼠標(biāo)單擊之間會(huì)被處理成雙擊事件的間隔時(shí)間
            GetEnvironmentStrings 為包含了當(dāng)前環(huán)境字串設(shè)置的一個(gè)內(nèi)存塊分配和返回一個(gè)句柄
            GetEnvironmentVariable 取得一個(gè)環(huán)境變量的值
            GetInputState 判斷是否存在任何待決(等待處理)的鼠標(biāo)或鍵盤(pán)事件
            GetKBCodePage 由GetOEMCP取代,兩者功能完全相同
            GetKeyboardLayout 取得一個(gè)句柄,描述指定應(yīng)用程序的鍵盤(pán)布局
            GetKeyboardLayoutList 獲得系統(tǒng)適用的所有鍵盤(pán)布局的一個(gè)列表
            GetKeyboardLayoutName 取得當(dāng)前活動(dòng)鍵盤(pán)布局的名稱(chēng)
            GetKeyboardState 取得鍵盤(pán)上每個(gè)虛擬鍵當(dāng)前的狀態(tài)
            GetKeyboardType 了解與正在使用的鍵盤(pán)有關(guān)的信息
            GetKeyNameText 在給出掃描碼的前提下,判斷鍵名
            GetKeyState 針對(duì)已處理過(guò)的按鍵,在最近一次輸入信息時(shí),判斷指定虛擬鍵的狀態(tài)
            GetLastError 針對(duì)之前調(diào)用的api函數(shù),用這個(gè)函數(shù)取得擴(kuò)展錯(cuò)誤信息
            GetLocaleInfo 取得與指定“地方”有關(guān)的信息
            GetLocalTime 取得本地日期和時(shí)間
            GetNumberFormat 針對(duì)指定的“地方”,按特定的格式格式化一個(gè)數(shù)字
            GetOEMCP 判斷在OEM和ANSI字符集間轉(zhuǎn)換的windows代碼頁(yè)
            GetQueueStatus 判斷應(yīng)用程序消息隊(duì)列中待決(等待處理)的消息類(lèi)型
            GetSysColor 判斷指定windows顯示對(duì)象的顏色
            GetSystemDefaultLangID 取得系統(tǒng)的默認(rèn)語(yǔ)言ID
            GetSystemDefaultLCID 取得當(dāng)前的默認(rèn)系統(tǒng)“地方”
            GetSystemInfo 取得與底層硬件平臺(tái)有關(guān)的信息
            GetSystemMetrics 返回與windows環(huán)境有關(guān)的信息
            GetSystemPowerStatus 獲得與當(dāng)前系統(tǒng)電源狀態(tài)有關(guān)的信息
            GetSystemTime 取得當(dāng)前系統(tǒng)時(shí)間,這個(gè)時(shí)間采用的是“協(xié)同世界時(shí)間”(即UTC,也叫做GMT)格式
            GetSystemTimeAdjustment 使內(nèi)部系統(tǒng)時(shí)鐘與一個(gè)外部的時(shí)鐘信號(hào)源同步
            GetThreadLocale 取得當(dāng)前線程的地方ID
            GetTickCount 用于獲取自windows啟動(dòng)以來(lái)經(jīng)歷的時(shí)間長(zhǎng)度(毫秒)
            GetTimeFormat 針對(duì)當(dāng)前指定的“地方”,按特定的格式格式化一個(gè)系統(tǒng)時(shí)間
            GetTimeZoneInformation 取得與系統(tǒng)時(shí)區(qū)設(shè)置有關(guān)的信息
            GetUserDefaultLangID 為當(dāng)前用戶(hù)取得默認(rèn)語(yǔ)言ID
            GetUserDefaultLCID 取得當(dāng)前用戶(hù)的默認(rèn)“地方”設(shè)置
            GetUserName 取得當(dāng)前用戶(hù)的名字
            GetVersion 判斷當(dāng)前運(yùn)行的Windows和DOS版本
            GetVersionEx 取得與平臺(tái)和操作系統(tǒng)有關(guān)的版本信息
            HideCaret 在指定的窗口隱藏插入符(光標(biāo))
            IsValidCodePage 判斷一個(gè)代碼頁(yè)是否有效
            IsValidLocale 判斷地方標(biāo)識(shí)符是否有效
            keybd_event 這個(gè)函數(shù)模擬了鍵盤(pán)行動(dòng)
            LoadKeyboardLayout 載入一個(gè)鍵盤(pán)布局
            MapVirtualKey 根據(jù)指定的映射類(lèi)型,執(zhí)行不同的掃描碼和字符轉(zhuǎn)換
            MapVirtualKeyEx 根據(jù)指定的映射類(lèi)型,執(zhí)行不同的掃描碼和字符轉(zhuǎn)換
            MessageBeep 播放一個(gè)系統(tǒng)聲音。系統(tǒng)聲音的分配方案是在控制面板里決定的
            mouse_event 模擬一次鼠標(biāo)事件
            OemKeyScan 判斷OEM字符集中的一個(gè)ASCII字符的掃描碼和Shift鍵狀態(tài)
            OemToChar 將OEM字符集的一個(gè)字串轉(zhuǎn)換到ANSI字符集
            SetCaretBlinkTime 指定插入符(光標(biāo))的閃爍頻率
            SetCaretPos 指定插入符的位置
            SetComputerName 設(shè)置新的計(jì)算機(jī)名
            SetCursor 將指定的鼠標(biāo)指針設(shè)為當(dāng)前指針
            SetCursorPos 設(shè)置指針的位置
            SetDoubleClickTime 設(shè)置連續(xù)兩次鼠標(biāo)單擊之間能使系統(tǒng)認(rèn)為是雙擊事件的間隔時(shí)間
            SetEnvironmentVariable 將一個(gè)環(huán)境變量設(shè)為指定的值
            SetKeyboardState 設(shè)置每個(gè)虛擬鍵當(dāng)前在鍵盤(pán)上的狀態(tài)
            SetLocaleInfo 改變用戶(hù)“地方”設(shè)置信息
            SetLocalTime 設(shè)置當(dāng)前地方時(shí)間
            SetSysColors 設(shè)置指定窗口顯示對(duì)象的顏色
            SetSystemCursor 改變?nèi)魏我粋€(gè)標(biāo)準(zhǔn)系統(tǒng)指針
            SetSystemTime 設(shè)置當(dāng)前系統(tǒng)時(shí)間
            SetSystemTimeAdjustment 定時(shí)添加一個(gè)校準(zhǔn)值使內(nèi)部系統(tǒng)時(shí)鐘與一個(gè)外部的時(shí)鐘信號(hào)源同步
            SetThreadLocale 為當(dāng)前線程設(shè)置地方
            SetTimeZoneInformation 設(shè)置系統(tǒng)時(shí)區(qū)信息
            ShowCaret 在指定的窗口里顯示插入符(光標(biāo))
            ShowCursor 控制鼠標(biāo)指針的可視性
            SwapMouseButton 決定是否互換鼠標(biāo)左右鍵的功能
            SystemParametersInfo 獲取和設(shè)置數(shù)量眾多的windows系統(tǒng)參數(shù)
            SystemTimeToTzSpecificLocalTime 將系統(tǒng)時(shí)間轉(zhuǎn)換成地方時(shí)間
            ToAscii 根據(jù)當(dāng)前的掃描碼和鍵盤(pán)信息,將一個(gè)虛擬鍵轉(zhuǎn)換成ASCII字符
            ToUnicode 根據(jù)當(dāng)前的掃描碼和鍵盤(pán)信息,將一個(gè)虛擬鍵轉(zhuǎn)換成Unicode字符
            UnloadKeyboardLayout 卸載指定的鍵盤(pán)布局
            VkKeyScan 針對(duì)Windows字符集中一個(gè)ASCII字符,判斷虛擬鍵碼和Shift鍵的狀態(tài)

            11. API之進(jìn)程和線程函數(shù)

            CancelWaitableTimer 這個(gè)函數(shù)用于取消一個(gè)可以等待下去的計(jì)時(shí)器操作
            CallNamedPipe 這個(gè)函數(shù)由一個(gè)希望通過(guò)管道通信的一個(gè)客戶(hù)進(jìn)程調(diào)用
            ConnectNamedPipe 指示一臺(tái)服務(wù)器等待下去,直至客戶(hù)機(jī)同一個(gè)命名管道連接
            CreateEvent 創(chuàng)建一個(gè)事件對(duì)象
            CreateMailslot 創(chuàng)建一個(gè)郵路。返回的句柄由郵路服務(wù)器使用(收件人)
            CreateMutex 創(chuàng)建一個(gè)互斥體(MUTEX)
            CreateNamedPipe 創(chuàng)建一個(gè)命名管道。返回的句柄由管道的服務(wù)器端使用
            CreatePipe 創(chuàng)建一個(gè)匿名管道
            CreateProcess 創(chuàng)建一個(gè)新進(jìn)程(比如執(zhí)行一個(gè)程序)
            CreateSemaphore 創(chuàng)建一個(gè)新的信號(hào)機(jī)
            CreateWaitableTimer 創(chuàng)建一個(gè)可等待的計(jì)時(shí)器對(duì)象
            DisconnectNamedPipe 斷開(kāi)一個(gè)客戶(hù)與一個(gè)命名管道的連接
            DuplicateHandle 在指出一個(gè)現(xiàn)有系統(tǒng)對(duì)象當(dāng)前句柄的情況下,為那個(gè)對(duì)象創(chuàng)建一個(gè)新句柄
            ExitProcess 中止一個(gè)進(jìn)程
            FindCloseChangeNotification 關(guān)閉一個(gè)改動(dòng)通知對(duì)象
            FindExecutable 查找與一個(gè)指定文件關(guān)聯(lián)在一起的程序的文件名
            FindFirstChangeNotification 創(chuàng)建一個(gè)文件通知對(duì)象。該對(duì)象用于監(jiān)視文件系統(tǒng)發(fā)生的變化
            FindNextChangeNotification 重設(shè)一個(gè)文件改變通知對(duì)象,令其繼續(xù)監(jiān)視下一次變化
            FreeLibrary 釋放指定的動(dòng)態(tài)鏈接庫(kù)
            GetCurrentProcess 獲取當(dāng)前進(jìn)程的一個(gè)偽句柄
            GetCurrentProcessId 獲取當(dāng)前進(jìn)程一個(gè)唯一的標(biāo)識(shí)符
            GetCurrentThread 獲取當(dāng)前線程的一個(gè)偽句柄
            GetCurrentThreadId 獲取當(dāng)前線程一個(gè)唯一的線程標(biāo)識(shí)符
            GetExitCodeProces 獲取一個(gè)已中斷進(jìn)程的退出代碼
            GetExitCodeThread 獲取一個(gè)已中止線程的退出代碼
            GetHandleInformation 獲取與一個(gè)系統(tǒng)對(duì)象句柄有關(guān)的信息
            GetMailslotInfo 獲取與一個(gè)郵路有關(guān)的信息
            GetModuleFileName 獲取一個(gè)已裝載模板的完整路徑名稱(chēng)
            GetModuleHandle 獲取一個(gè)應(yīng)用程序或動(dòng)態(tài)鏈接庫(kù)的模塊句柄
            GetPriorityClass 獲取特定進(jìn)程的優(yōu)先級(jí)別
            GetProcessShutdownParameters 調(diào)查系統(tǒng)關(guān)閉時(shí)一個(gè)指定的進(jìn)程相對(duì)于其它進(jìn)程的關(guān)閉早遲情況
            GetProcessTimes 獲取與一個(gè)進(jìn)程的經(jīng)過(guò)時(shí)間有關(guān)的信息
            GetProcessWorkingSetSize 了解一個(gè)應(yīng)用程序在運(yùn)行過(guò)程中實(shí)際向它交付了多大容量的內(nèi)存
            GetSartupInfo 獲取一個(gè)進(jìn)程的啟動(dòng)信息
            GetThreadPriority 獲取特定線程的優(yōu)先級(jí)別
            GetTheardTimes 獲取與一個(gè)線程的經(jīng)過(guò)時(shí)間有關(guān)的信息
            GetWindowThreadProcessId 獲取與指定窗口關(guān)聯(lián)在一起的一個(gè)進(jìn)程和線程標(biāo)識(shí)符
            LoadLibrary 載入指定的動(dòng)態(tài)鏈接庫(kù),并將它映射到當(dāng)前進(jìn)程使用的地址空間
            LoadLibraryEx 裝載指定的動(dòng)態(tài)鏈接庫(kù),并為當(dāng)前進(jìn)程把它映射到地址空間
            LoadModule 載入一個(gè)Windows應(yīng)用程序,并在指定的環(huán)境中運(yùn)行
            MsgWaitForMultipleObjects 等侯單個(gè)對(duì)象或一系列對(duì)象發(fā)出信號(hào)。如返回條件已經(jīng)滿(mǎn)足,則立即返回
            SetPriorityClass 設(shè)置一個(gè)進(jìn)程的優(yōu)先級(jí)別
            SetProcessShutdownParameters 在系統(tǒng)關(guān)閉期間,為指定進(jìn)程設(shè)置他相對(duì)于其它程序的關(guān)閉順序
            SetProcessWorkingSetSize 設(shè)置操作系統(tǒng)實(shí)際劃分給進(jìn)程使用的內(nèi)存容量
            SetThreadPriority 設(shè)定線程的優(yōu)先級(jí)別
            ShellExecute 查找與指定文件關(guān)聯(lián)在一起的程序的文件名
            TerminateProcess 結(jié)束一個(gè)進(jìn)程
            WinExec 運(yùn)行指定的程序

            12. API之控件與消息函數(shù)

            AdjustWindowRect 給定一種窗口樣式,計(jì)算獲得目標(biāo)客戶(hù)區(qū)矩形所需的窗口大小
            AnyPopup 判斷屏幕上是否存在任何彈出式窗口
            ArrangeIconicWindows 排列一個(gè)父窗口的最小化子窗口
            AttachThreadInput 連接線程輸入函數(shù)
            BeginDeferWindowPos 啟動(dòng)構(gòu)建一系列新窗口位置的過(guò)程
            BringWindowToTop 將指定的窗口帶至窗口列表頂部
            CascadeWindows 以層疊方式排列窗口
            ChildWindowFromPoint 返回父窗口中包含了指定點(diǎn)的第一個(gè)子窗口的句柄
            ClientToScreen 判斷窗口內(nèi)以客戶(hù)區(qū)坐標(biāo)表示的一個(gè)點(diǎn)的屏幕坐標(biāo)
            CloseWindow 最小化指定的窗口
            CopyRect 矩形內(nèi)容復(fù)制
            DeferWindowPos 該函數(shù)為特定的窗口指定一個(gè)新窗口位置
            DestroyWindow 清除指定的窗口以及它的所有子窗口
            DrawAnimatedRects 描繪一系列動(dòng)態(tài)矩形
            EnableWindow 指定的窗口里允許或禁止所有鼠標(biāo)及鍵盤(pán)輸入
            EndDeferWindowPos 同時(shí)更新DeferWindowPos調(diào)用時(shí)指定的所有窗口的位置及狀態(tài)
            EnumChildWindows 為指定的父窗口枚舉子窗口
            EnumThreadWindows 枚舉與指定任務(wù)相關(guān)的窗口
            EnumWindows 枚舉窗口列表中的所有父窗口
            EqualRect 判斷兩個(gè)矩形結(jié)構(gòu)是否相同
            FindWindow 尋找窗口列表中第一個(gè)符合指定條件的頂級(jí)窗口
            FindWindowEx 在窗口列表中尋找與指定條件相符的第一個(gè)子窗口
            FlashWindow 閃爍顯示指定窗口
            GetActiveWindow 獲得活動(dòng)窗口的句柄
            GetCapture 獲得一個(gè)窗口的句柄,這個(gè)窗口位于當(dāng)前輸入線程,且擁有鼠標(biāo)捕獲(鼠標(biāo)活動(dòng)由它接收)
            GetClassInfo 取得WNDCLASS結(jié)構(gòu)(或WNDCLASSEX結(jié)構(gòu))的一個(gè)副本,結(jié)構(gòu)中包含了與指定類(lèi)有關(guān)的信息
            GetClassLong 取得窗口類(lèi)的一個(gè)Long變量條目
            GetClassName 為指定的窗口取得類(lèi)名
            GetClassWord 為窗口類(lèi)取得一個(gè)整數(shù)變量
            GetClientRect 返回指定窗口客戶(hù)區(qū)矩形的大小
            GetDesktopWindow 獲得代表整個(gè)屏幕的一個(gè)窗口(桌面窗口)句柄
            GetFocus 獲得擁有輸入焦點(diǎn)的窗口的句柄
            GetForegroundWindow 獲得前臺(tái)窗口的句柄
            GetLastActivePopup 獲得在一個(gè)給定父窗口中最近激活過(guò)的彈出式窗口的句柄
            GetParent 判斷指定窗口的父窗口
            GetTopWindow 搜索內(nèi)部窗口列表,尋找隸屬于指定窗口的頭一個(gè)窗口的句柄
            GetUpdateRect 獲得一個(gè)矩形,它描敘了指定窗口中需要更新的那一部分
            GetWindow 獲得一個(gè)窗口的句柄,該窗口與某源窗口有特定的關(guān)系
            GetWindowContextHelpId 取得與窗口關(guān)聯(lián)在一起的幫助場(chǎng)景ID
            GetWindowLong 從指定窗口的結(jié)構(gòu)中取得信息
            GetWindowPlacement 獲得指定窗口的狀態(tài)及位置信息
            GetWindowRect 獲得整個(gè)窗口的范圍矩形,窗口的邊框、標(biāo)題欄、滾動(dòng)條及菜單等都在這個(gè)矩形內(nèi)
            GetWindowText 取得一個(gè)窗體的標(biāo)題(caption)文字,或者一個(gè)控件的內(nèi)容
            GetWindowTextLength 調(diào)查窗口標(biāo)題文字或控件內(nèi)容的長(zhǎng)短
            GetWindowWord 獲得指定窗口結(jié)構(gòu)的信息
            InflateRect 增大或減小一個(gè)矩形的大小
            IntersectRect 這個(gè)函數(shù)在lpDestRect里載入一個(gè)矩形,它是lpSrc1Rect與lpSrc2Rect兩個(gè)矩形的交集
            InvalidateRect 屏蔽一個(gè)窗口客戶(hù)區(qū)的全部或部分區(qū)域
            IsChild 判斷一個(gè)窗口是否為另一窗口的子或隸屬窗口
            IsIconic 判斷窗口是否已最小化
            IsRectEmpty 判斷一個(gè)矩形是否為空
            IsWindow 判斷一個(gè)窗口句柄是否有效
            IsWindowEnabled 判斷窗口是否處于活動(dòng)狀態(tài)
            IsWindowUnicode 判斷一個(gè)窗口是否為Unicode窗口。這意味著窗口為所有基于文本的消息都接收Unicode文字
            IsWindowVisible 判斷窗口是否可見(jiàn)
            IsZoomed 判斷窗口是否最大化
            LockWindowUpdate 鎖定指定窗口,禁止它更新
            MapWindowPoints 將一個(gè)窗口客戶(hù)區(qū)坐標(biāo)的點(diǎn)轉(zhuǎn)換到另一窗口的客戶(hù)區(qū)坐標(biāo)系統(tǒng)
            MoveWindow 改變指定窗口的位置和大小
            OffsetRect 通過(guò)應(yīng)用一個(gè)指定的偏移,從而讓矩形移動(dòng)起來(lái)
            OpenIcon 恢復(fù)一個(gè)最小化的程序,并將其激活
            PtInRect 判斷指定的點(diǎn)是否位于矩形內(nèi)部
            RedrawWindow 重畫(huà)全部或部分窗口
            ReleaseCapture 為當(dāng)前的應(yīng)用程序釋放鼠標(biāo)捕獲
            ScreenToClient 判斷屏幕上一個(gè)指定點(diǎn)的客戶(hù)區(qū)坐標(biāo)
            ScrollWindow 滾動(dòng)窗口客戶(hù)區(qū)的全部或一部分
            ScrollWindowEx 根據(jù)附加的選項(xiàng),滾動(dòng)窗口客戶(hù)區(qū)的全部或部分
            SetActiveWindow 激活指定的窗口
            SetCapture 將鼠標(biāo)捕獲設(shè)置到指定的窗口
            SetClassLong 為窗口類(lèi)設(shè)置一個(gè)Long變量條目
            SetClassWord 為窗口類(lèi)設(shè)置一個(gè)條目
            SetFocusAPI 將輸入焦點(diǎn)設(shè)到指定的窗口。如有必要,會(huì)激活窗口
            SetForegroundWindow 將窗口設(shè)為系統(tǒng)的前臺(tái)窗口
            SetParent 指定一個(gè)窗口的新父
            SetRect 設(shè)置指定矩形的內(nèi)容
            SetRectEmpty 將矩形設(shè)為一個(gè)空矩形
            SetWindowContextHelpId 為指定的窗口設(shè)置幫助場(chǎng)景(上下文)ID
            SetWindowLong 在窗口結(jié)構(gòu)中為指定的窗口設(shè)置信息
            SetWindowPlacement 設(shè)置窗口狀態(tài)和位置信息
            SetWindowPos 為窗口指定一個(gè)新位置和狀態(tài)
            SetWindowText 設(shè)置窗口的標(biāo)題文字或控件的內(nèi)容
            SetWindowWord 在窗口結(jié)構(gòu)中為指定的窗口設(shè)置信息
            ShowOwnedPopups 顯示或隱藏由指定窗口所有的全部彈出式窗口
            ShowWindow 控制窗口的可見(jiàn)性
            ShowWindowAsync 與ShowWindow相似
            SubtractRect 裝載矩形lprcDst,它是在矩形lprcSrc1中減去lprcSrc2得到的結(jié)果
            TileWindows 以平鋪?lái)樞蚺帕写翱?br>UnionRect 裝載一個(gè)lpDestRect目標(biāo)矩形,它是lpSrc1Rect和lpSrc2Rect聯(lián)合起來(lái)的結(jié)果
            UpdateWindow 強(qiáng)制立即更新窗口
            ValidateRect 校驗(yàn)窗口的全部或部分客戶(hù)區(qū)
            WindowFromPoint 返回包含了指定點(diǎn)的窗口的句柄。忽略屏蔽、隱藏以及透明窗口

            消息,就是指Windows發(fā)出的一個(gè)通知,告訴應(yīng)用程序某個(gè)事情發(fā)生了。例如,單擊鼠標(biāo)、改變窗口尺寸、按下鍵盤(pán)上的一個(gè)鍵都會(huì)使Windows 發(fā)送一個(gè)消息給應(yīng)用程序。消息本身是作為一個(gè)記錄傳遞給應(yīng)用程序的,這個(gè)記錄中包含了消息的類(lèi)型以及其他信息。例如,對(duì)于單擊鼠標(biāo)所產(chǎn)生的消息來(lái)說(shuō),這個(gè) 記錄中包含了單擊鼠標(biāo)時(shí)的坐標(biāo)。這個(gè)記錄類(lèi)型叫做TMsg,

            它在Windows單元中是這樣聲明的:
            type
            TMsg = packed record
            hwnd: HWND; / /窗口句柄
            message: UINT; / /消息常量標(biāo)識(shí)符
            wParam: WPARAM ; // 32位消息的特定附加信息
            lParam: LPARAM ; // 32位消息的特定附加信息
            time: DWORD; / /消息創(chuàng)建時(shí)的時(shí)間
            pt: TPoint; / /消息創(chuàng)建時(shí)的鼠標(biāo)位置
            end;


            posted @ 2008-08-28 10:30 深邃者 閱讀(433) | 評(píng)論 (0)編輯 收藏

            Window API函數(shù)大全(3)

            再補(bǔ)一點(diǎn)消息詳解
            消息中有什么?
            是否覺(jué)得一個(gè)消息記錄中的信息像希臘語(yǔ)一樣?如果是這樣,那么看一看下面的解釋?zhuān)?br>hwnd 32位的窗口句柄。窗口可以是任何類(lèi)型的屏幕對(duì)象,因?yàn)閃in32能夠維護(hù)大多數(shù)可視對(duì)象的句柄(窗口、對(duì)話框、按鈕、編輯框等)。
            message 用于區(qū)別其他消息的常量值,這些常量可以是Windows單元中預(yù)定義的常量,也可以是自定義的常量。
            wParam 通常是一個(gè)與消息有關(guān)的常量值,也可能是窗口或控件的句柄。
            lParam 通常是一個(gè)指向內(nèi)存中數(shù)據(jù)的指針。由于W P a r a m、l P a r a m和P o i n t e r都是3 2位的,
            因此,它們之間可以相互轉(zhuǎn)換。

            WM_NULL = $0000;
            WM_CREATE = $0001;
            應(yīng)用程序創(chuàng)建一個(gè)窗口
            WM_DESTROY = $0002;
            一個(gè)窗口被銷(xiāo)毀
            WM_MOVE = $0003;
            移動(dòng)一個(gè)窗口
            WM_SIZE = $0005;
            改變一個(gè)窗口的大小
            WM_ACTIVATE = $0006;
            一個(gè)窗口被激活或失去激活狀態(tài);
            WM_SETFOCUS = $0007;
            獲得焦點(diǎn)后
            WM_KILLFOCUS = $0008;
            失去焦點(diǎn)
            WM_ENABLE = $000A;
            改變enable狀態(tài)
            WM_SETREDRAW = $000B;
            設(shè)置窗口是否能重畫(huà)
            WM_SETTEXT = $000C;
            應(yīng)用程序發(fā)送此消息來(lái)設(shè)置一個(gè)窗口的文本
            WM_GETTEXT = $000D;
            應(yīng)用程序發(fā)送此消息來(lái)復(fù)制對(duì)應(yīng)窗口的文本到緩沖區(qū)
            WM_GETTEXTLENGTH = $000E;
            得到與一個(gè)窗口有關(guān)的文本的長(zhǎng)度(不包含空字符)
            WM_PAINT = $000F;
            要求一個(gè)窗口重畫(huà)自己
            WM_CLOSE = $0010;
            當(dāng)一個(gè)窗口或應(yīng)用程序要關(guān)閉時(shí)發(fā)送一個(gè)信號(hào)
            WM_QUERYENDSESSION = $0011;
            當(dāng)用戶(hù)選擇結(jié)束對(duì)話框或程序自己調(diào)用ExitWindows函數(shù)
            WM_QUIT = $0012;
            用來(lái)結(jié)束程序運(yùn)行或當(dāng)程序調(diào)用postquitmessage函數(shù)
            WM_QUERYOPEN = $0013;
            當(dāng)用戶(hù)窗口恢復(fù)以前的大小位置時(shí),把此消息發(fā)送給某個(gè)圖標(biāo)
            WM_ERASEBKGND = $0014;
            當(dāng)窗口背景必須被擦除時(shí)(例在窗口改變大小時(shí))
            WM_SYSCOLORCHANGE = $0015;
            當(dāng)系統(tǒng)顏色改變時(shí),發(fā)送此消息給所有頂級(jí)窗口
            WM_ENDSESSION = $0016;
            當(dāng)系統(tǒng)進(jìn)程發(fā)出WM_QUERYENDSESSION消息后,此消息發(fā)送給應(yīng)用程序,
            通知它對(duì)話是否結(jié)束
            WM_SYSTEMERROR = $0017;
            WM_SHOWWINDOW = $0018;
            當(dāng)隱藏或顯示窗口是發(fā)送此消息給這個(gè)窗口
            WM_ACTIVATEAPP = $001C;
            發(fā)此消息給應(yīng)用程序哪個(gè)窗口是激活的,哪個(gè)是非激活的;
            WM_FONTCHANGE = $001D;
            當(dāng)系統(tǒng)的字體資源庫(kù)變化時(shí)發(fā)送此消息給所有頂級(jí)窗口
            WM_TIMECHANGE = $001E;
            當(dāng)系統(tǒng)的時(shí)間變化時(shí)發(fā)送此消息給所有頂級(jí)窗口
            WM_CANCELMODE = $001F;
            發(fā)送此消息來(lái)取消某種正在進(jìn)行的摸態(tài)(操作)
            WM_SETCURSOR = $0020;
            如果鼠標(biāo)引起光標(biāo)在某個(gè)窗口中移動(dòng)且鼠標(biāo)輸入沒(méi)有被捕獲時(shí),就發(fā)消息給某個(gè)窗口
            WM_MOUSEACTIVATE = $0021;
            當(dāng)光標(biāo)在某個(gè)非激活的窗口中而用戶(hù)正按著鼠標(biāo)的某個(gè)鍵發(fā)送此消息給當(dāng)前窗口
            WM_CHILDACTIVATE = $0022;
            發(fā)送此消息給MDI子窗口當(dāng)用戶(hù)點(diǎn)擊此窗口的標(biāo)題欄,或當(dāng)窗口被激活,移動(dòng),改變大小
            WM_QUEUESYNC = $0023;
            此消息由基于計(jì)算機(jī)的訓(xùn)練程序發(fā)送,通過(guò)WH_JOURNALPALYBACK的hook程序
            分離出用戶(hù)輸入消息
            WM_GETMINMAXINFO = $0024;
            此消息發(fā)送給窗口當(dāng)它將要改變大小或位置;
            WM_PAINTICON = $0026;
            發(fā)送給最小化窗口當(dāng)它圖標(biāo)將要被重畫(huà)
            WM_ICONERASEBKGND = $0027;
            此消息發(fā)送給某個(gè)最小化窗口,僅當(dāng)它在畫(huà)圖標(biāo)前它的背景必須被重畫(huà)
            WM_NEXTDLGCTL = $0028;
            發(fā)送此消息給一個(gè)對(duì)話框程序去更改焦點(diǎn)位置
            WM_SPOOLERSTATUS = $002A;
            每當(dāng)打印管理列隊(duì)增加或減少一條作業(yè)時(shí)發(fā)出此消息
            WM_DRAWITEM = $002B;
            當(dāng)button,combobox,listbox,menu的可視外觀改變時(shí)發(fā)送
            此消息給這些空件的所有者
            WM_MEASUREITEM = $002C;
            當(dāng)button, combo box, list box, list view control, or menu item 被創(chuàng)建時(shí)
            發(fā)送此消息給控件的所有者
            WM_DELETEITEM = $002D;
            當(dāng)the list box 或 combo box 被銷(xiāo)毀 或 當(dāng) 某些項(xiàng)被刪除通過(guò)LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT 消息
            WM_VKEYTOITEM = $002E;
            此消息有一個(gè)LBS_WANTKEYBOARDINPUT風(fēng)格的發(fā)出給它的所有者來(lái)響應(yīng)WM_KEYDOWN消息
            WM_CHARTOITEM = $002F;
            此消息由一個(gè)LBS_WANTKEYBOARDINPUT風(fēng)格的列表框發(fā)送給他的所有者來(lái)響應(yīng)WM_CHAR消息
            WM_SETFONT = $0030;
            當(dāng)繪制文本時(shí)程序發(fā)送此消息得到控件要用的顏色
            WM_GETFONT = $0031;
            應(yīng)用程序發(fā)送此消息得到當(dāng)前控件繪制文本的字體
            WM_SETHOTKEY = $0032;
            應(yīng)用程序發(fā)送此消息讓一個(gè)窗口與一個(gè)熱鍵相關(guān)連
            WM_GETHOTKEY = $0033;
            應(yīng)用程序發(fā)送此消息來(lái)判斷熱鍵與某個(gè)窗口是否有關(guān)聯(lián)
            WM_QUERYDRAGICON = $0037;
            此消息發(fā)送給最小化窗口,當(dāng)此窗口將要被拖放而它的類(lèi)中沒(méi)有定義圖標(biāo),應(yīng)用程序能返回一個(gè)圖標(biāo)或光標(biāo)的句柄,當(dāng)用戶(hù)拖放圖標(biāo)時(shí)系統(tǒng)顯示這個(gè)圖標(biāo)或光標(biāo)
            WM_COMPAREITEM = $0039;
            發(fā)送此消息來(lái)判定combobox或listbox新增加的項(xiàng)的相對(duì)位置
            WM_GETOBJECT = $003D;
            WM_COMPACTING = $0041;
            顯示內(nèi)存已經(jīng)很少了
            WM_WINDOWPOSCHANGING = $0046;
            發(fā)送此消息給那個(gè)窗口的大小和位置將要被改變時(shí),來(lái)調(diào)用setwindowpos函數(shù)或其它窗口管理函數(shù)
            WM_WINDOWPOSCHANGED = $0047;
            發(fā)送此消息給那個(gè)窗口的大小和位置已經(jīng)被改變時(shí),來(lái)調(diào)用setwindowpos函數(shù)或其它窗口管理函數(shù)
            WM_POWER = $0048;(適用于16位的windows)
            當(dāng)系統(tǒng)將要進(jìn)入暫停狀態(tài)時(shí)發(fā)送此消息
            WM_COPYDATA = $004A;
            當(dāng)一個(gè)應(yīng)用程序傳遞數(shù)據(jù)給另一個(gè)應(yīng)用程序時(shí)發(fā)送此消息
            WM_CANCELJOURNAL = $004B;
            當(dāng)某個(gè)用戶(hù)取消程序日志激活狀態(tài),提交此消息給程序
            WM_NOTIFY = $004E;
            當(dāng)某個(gè)控件的某個(gè)事件已經(jīng)發(fā)生或這個(gè)控件需要得到一些信息時(shí),發(fā)送此消息給它的父窗口
            WM_INPUTLANGCHANGEREQUEST = $0050;
            當(dāng)用戶(hù)選擇某種輸入語(yǔ)言,或輸入語(yǔ)言的熱鍵改變
            WM_INPUTLANGCHANGE = $0051;
            當(dāng)平臺(tái)現(xiàn)場(chǎng)已經(jīng)被改變后發(fā)送此消息給受影響的最頂級(jí)窗口
            WM_TCARD = $0052;
            當(dāng)程序已經(jīng)初始化windows幫助例程時(shí)發(fā)送此消息給應(yīng)用程序
            WM_HELP = $0053;
            此消息顯示用戶(hù)按下了F1,如果某個(gè)菜單是激活的,就發(fā)送此消息個(gè)此窗口關(guān)聯(lián)的菜單,否則就
            發(fā)送給有焦點(diǎn)的窗口,如果當(dāng)前都沒(méi)有焦點(diǎn),就把此消息發(fā)送給當(dāng)前激活的窗口
            WM_USERCHANGED = $0054;
            當(dāng)用戶(hù)已經(jīng)登入或退出后發(fā)送此消息給所有的窗口,當(dāng)用戶(hù)登入或退出時(shí)系統(tǒng)更新用戶(hù)的具體
            設(shè)置信息,在用戶(hù)更新設(shè)置時(shí)系統(tǒng)馬上發(fā)送此消息;
            WM_NOTIFYFORMAT = $0055;
            公用控件,自定義控件和他們的父窗口通過(guò)此消息來(lái)判斷控件是使用ANSI還是UNICODE結(jié)構(gòu)
            在WM_NOTIFY消息,使用此控件能使某個(gè)控件與它的父控件之間進(jìn)行相互通信
            WM_CONTEXTMENU = $007B;
            當(dāng)用戶(hù)某個(gè)窗口中點(diǎn)擊了一下右鍵就發(fā)送此消息給這個(gè)窗口
            WM_STYLECHANGING = $007C;
            當(dāng)調(diào)用SETWINDOWLONG函數(shù)將要改變一個(gè)或多個(gè) 窗口的風(fēng)格時(shí)發(fā)送此消息給那個(gè)窗口
            WM_STYLECHANGED = $007D;
            當(dāng)調(diào)用SETWINDOWLONG函數(shù)一個(gè)或多個(gè) 窗口的風(fēng)格后發(fā)送此消息給那個(gè)窗口
            WM_DISPLAYCHANGE = $007E;
            當(dāng)顯示器的分辨率改變后發(fā)送此消息給所有的窗口
            WM_GETICON = $007F;
            此消息發(fā)送給某個(gè)窗口來(lái)返回與某個(gè)窗口有關(guān)連的大圖標(biāo)或小圖標(biāo)的句柄;
            WM_SETICON = $0080;
            程序發(fā)送此消息讓一個(gè)新的大圖標(biāo)或小圖標(biāo)與某個(gè)窗口關(guān)聯(lián);
            WM_NCCREATE = $0081;
            當(dāng)某個(gè)窗口第一次被創(chuàng)建時(shí),此消息在WM_CREATE消息發(fā)送前發(fā)送;
            WM_NCDESTROY = $0082;
            此消息通知某個(gè)窗口,非客戶(hù)區(qū)正在銷(xiāo)毀
            WM_NCCALCSIZE = $0083;
            當(dāng)某個(gè)窗口的客戶(hù)區(qū)域必須被核算時(shí)發(fā)送此消息
            WM_NCHITTEST = $0084;//移動(dòng)鼠標(biāo),按住或釋放鼠標(biāo)時(shí)發(fā)生
            WM_NCPAINT = $0085;
            程序發(fā)送此消息給某個(gè)窗口當(dāng)它(窗口)的框架必須被繪制時(shí);
            WM_NCACTIVATE = $0086;
            此消息發(fā)送給某個(gè)窗口 僅當(dāng)它的非客戶(hù)區(qū)需要被改變來(lái)顯示是激活還是非激活狀態(tài);
            WM_GETDLGCODE = $0087;
            發(fā)送此消息給某個(gè)與對(duì)話框程序關(guān)聯(lián)的控件,widdows控制方位鍵和TAB鍵使輸入進(jìn)入此控件
            通過(guò)響應(yīng)WM_GETDLGCODE消息,應(yīng)用程序可以把他當(dāng)成一個(gè)特殊的輸入控件并能處理它
            WM_NCMOUSEMOVE = $00A0;
            當(dāng)光標(biāo)在一個(gè)窗口的非客戶(hù)區(qū)內(nèi)移動(dòng)時(shí)發(fā)送此消息給這個(gè)窗口 //非客戶(hù)區(qū)為:窗體的標(biāo)題欄及窗
            的邊框體
            WM_NCLBUTTONDOWN = $00A1;
            當(dāng)光標(biāo)在一個(gè)窗口的非客戶(hù)區(qū)同時(shí)按下鼠標(biāo)左鍵時(shí)提交此消息
            WM_NCLBUTTONUP = $00A2;
            當(dāng)用戶(hù)釋放鼠標(biāo)左鍵同時(shí)光標(biāo)某個(gè)窗口在非客戶(hù)區(qū)十發(fā)送此消息;
            WM_NCLBUTTONDBLCLK = $00A3;
            當(dāng)用戶(hù)雙擊鼠標(biāo)左鍵同時(shí)光標(biāo)某個(gè)窗口在非客戶(hù)區(qū)十發(fā)送此消息
            WM_NCRBUTTONDOWN = $00A4;
            當(dāng)用戶(hù)按下鼠標(biāo)右鍵同時(shí)光標(biāo)又在窗口的非客戶(hù)區(qū)時(shí)發(fā)送此消息
            WM_NCRBUTTONUP = $00A5;
            當(dāng)用戶(hù)釋放鼠標(biāo)右鍵同時(shí)光標(biāo)又在窗口的非客戶(hù)區(qū)時(shí)發(fā)送此消息
            WM_NCRBUTTONDBLCLK = $00A6;
            當(dāng)用戶(hù)雙擊鼠標(biāo)右鍵同時(shí)光標(biāo)某個(gè)窗口在非客戶(hù)區(qū)十發(fā)送此消息
            WM_NCMBUTTONDOWN = $00A7;
            當(dāng)用戶(hù)按下鼠標(biāo)中鍵同時(shí)光標(biāo)又在窗口的非客戶(hù)區(qū)時(shí)發(fā)送此消息
            WM_NCMBUTTONUP = $00A8;
            當(dāng)用戶(hù)釋放鼠標(biāo)中鍵同時(shí)光標(biāo)又在窗口的非客戶(hù)區(qū)時(shí)發(fā)送此消息
            WM_NCMBUTTONDBLCLK = $00A9;
            當(dāng)用戶(hù)雙擊鼠標(biāo)中鍵同時(shí)光標(biāo)又在窗口的非客戶(hù)區(qū)時(shí)發(fā)送此消息
            WM_KEYFIRST = $0100;
            WM_KEYDOWN = $0100;
            //按下一個(gè)鍵
            WM_KEYUP = $0101;
            //釋放一個(gè)鍵
            WM_CHAR = $0102;
            //按下某鍵,并已發(fā)出WM_KEYDOWN, WM_KEYUP消息
            WM_DEADCHAR = $0103;
            當(dāng)用translatemessage函數(shù)翻譯WM_KEYUP消息時(shí)發(fā)送此消息給擁有焦點(diǎn)的窗口
            WM_SYSKEYDOWN = $0104;
            當(dāng)用戶(hù)按住ALT鍵同時(shí)按下其它鍵時(shí)提交此消息給擁有焦點(diǎn)的窗口;
            WM_SYSKEYUP = $0105;
            當(dāng)用戶(hù)釋放一個(gè)鍵同時(shí)ALT 鍵還按著時(shí)提交此消息給擁有焦點(diǎn)的窗口
            WM_SYSCHAR = $0106;
            當(dāng)WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函數(shù)翻譯后提交此消息給擁有焦點(diǎn)的窗口
            WM_SYSDEADCHAR = $0107;
            當(dāng)WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函數(shù)翻譯后發(fā)送此消息給擁有焦點(diǎn)的窗口
            WM_KEYLAST = $0108;
            WM_INITDIALOG = $0110;
            在一個(gè)對(duì)話框程序被顯示前發(fā)送此消息給它,通常用此消息初始化控件和執(zhí)行其它任務(wù)
            WM_COMMAND = $0111;
            當(dāng)用戶(hù)選擇一條菜單命令項(xiàng)或當(dāng)某個(gè)控件發(fā)送一條消息給它的父窗口,一個(gè)快捷鍵被翻譯
            WM_SYSCOMMAND = $0112;
            當(dāng)用戶(hù)選擇窗口菜單的一條命令或當(dāng)用戶(hù)選擇最大化或最小化時(shí)那個(gè)窗口會(huì)收到此消息
            WM_TIMER = $0113; //發(fā)生了定時(shí)器事件
            WM_HSCROLL = $0114;
            當(dāng)一個(gè)窗口標(biāo)準(zhǔn)水平滾動(dòng)條產(chǎn)生一個(gè)滾動(dòng)事件時(shí)發(fā)送此消息給那個(gè)窗口,也發(fā)送給擁有它的控件
            WM_VSCROLL = $0115;
            當(dāng)一個(gè)窗口標(biāo)準(zhǔn)垂直滾動(dòng)條產(chǎn)生一個(gè)滾動(dòng)事件時(shí)發(fā)送此消息給那個(gè)窗口也,發(fā)送給擁有它的控件 WM_INITMENU = $0116;
            當(dāng)一個(gè)菜單將要被激活時(shí)發(fā)送此消息,它發(fā)生在用戶(hù)菜單條中的某項(xiàng)或按下某個(gè)菜單鍵,它允許程序在顯示前更改菜單
            WM_INITMENUPOPUP = $0117;
            當(dāng)一個(gè)下拉菜單或子菜單將要被激活時(shí)發(fā)送此消息,它允許程序在它顯示前更改菜單,而不要改變?nèi)?
            WM_MENUSELECT = $011F;
            當(dāng)用戶(hù)選擇一條菜單項(xiàng)時(shí)發(fā)送此消息給菜單的所有者(一般是窗口)
            WM_MENUCHAR = $0120;
            當(dāng)菜單已被激活用戶(hù)按下了某個(gè)鍵(不同于加速鍵),發(fā)送此消息給菜單的所有者;
            WM_ENTERIDLE = $0121;
            當(dāng)一個(gè)模態(tài)對(duì)話框或菜單進(jìn)入空載狀態(tài)時(shí)發(fā)送此消息給它的所有者,一個(gè)模態(tài)對(duì)話框或菜單進(jìn)入空載狀態(tài)就是在處理完一條或幾條先前的消息后沒(méi)有消息它的列隊(duì)中等待
            WM_MENURBUTTONUP = $0122;
            WM_MENUDRAG = $0123;
            WM_MENUGETOBJECT = $0124;
            WM_UNINITMENUPOPUP = $0125;
            WM_MENUCOMMAND = $0126;
            WM_CHANGEUISTATE = $0127;
            WM_UPDATEUISTATE = $0128;
            WM_QUERYUISTATE = $0129;
            WM_CTLCOLORMSGBOX = $0132;
            在windows繪制消息框前發(fā)送此消息給消息框的所有者窗口,通過(guò)響應(yīng)這條消息,所有者窗口可以通過(guò)使用給定的相關(guān)顯示設(shè)備的句柄來(lái)設(shè)置消息框的文本和背景顏色
            WM_CTLCOLOREDIT = $0133;
            當(dāng)一個(gè)編輯型控件將要被繪制時(shí)發(fā)送此消息給它的父窗口;通過(guò)響應(yīng)這條消息,所有者窗口可以通過(guò)使用給定的相關(guān)顯示設(shè)備的句柄來(lái)設(shè)置編輯框的文本和背景顏色
            WM_CTLCOLORLISTBOX = $0134;
            當(dāng)一個(gè)列表框控件將要被繪制前發(fā)送此消息給它的父窗口;通過(guò)響應(yīng)這條消息,所有者窗口可以通過(guò)使用給定的相關(guān)顯示設(shè)備的句柄來(lái)設(shè)置列表框的文本和背景顏色
            WM_CTLCOLORBTN = $0135;
            當(dāng)一個(gè)按鈕控件將要被繪制時(shí)發(fā)送此消息給它的父窗口;通過(guò)響應(yīng)這條消息,所有者窗口可以通過(guò)使用給定的相關(guān)顯示設(shè)備的句柄來(lái)設(shè)置按紐的文本和背景顏色
            WM_CTLCOLORDLG = $0136;
            當(dāng)一個(gè)對(duì)話框控件將要被繪制前發(fā)送此消息給它的父窗口;通過(guò)響應(yīng)這條消息,所有者窗口可以通過(guò)使用給定的相關(guān)顯示設(shè)備的句柄來(lái)設(shè)置對(duì)話框的文本背景顏色
            WM_CTLCOLORSCROLLBAR= $0137;
            當(dāng)一個(gè)滾動(dòng)條控件將要被繪制時(shí)發(fā)送此消息給它的父窗口;通過(guò)響應(yīng)這條消息,所有者窗口可以通過(guò)使用給定的相關(guān)顯示設(shè)備的句柄來(lái)設(shè)置滾動(dòng)條的背景顏色
            WM_CTLCOLORSTATIC = $0138;
            當(dāng)一個(gè)靜態(tài)控件將要被繪制時(shí)發(fā)送此消息給它的父窗口;通過(guò)響應(yīng)這條消息,所有者窗口可以通過(guò)使用給定的相關(guān)顯示設(shè)備的句柄來(lái)設(shè)置靜態(tài)控件的文本和背景顏色
            WM_MOUSEFIRST = $0200;
            WM_MOUSEMOVE = $0200;
            // 移動(dòng)鼠標(biāo)
            WM_LBUTTONDOWN = $0201;
            //按下鼠標(biāo)左鍵
            WM_LBUTTONUP = $0202;
            //釋放鼠標(biāo)左鍵
            WM_LBUTTONDBLCLK = $0203;
            //雙擊鼠標(biāo)左鍵
            WM_RBUTTONDOWN = $0204;
            //按下鼠標(biāo)右鍵
            WM_RBUTTONUP = $0205;
            //釋放鼠標(biāo)右鍵
            WM_RBUTTONDBLCLK = $0206;
            //雙擊鼠標(biāo)右鍵
            WM_MBUTTONDOWN = $0207;
            //按下鼠標(biāo)中鍵
            WM_MBUTTONUP = $0208;
            //釋放鼠標(biāo)中鍵
            WM_MBUTTONDBLCLK = $0209;
            //雙擊鼠標(biāo)中鍵
            WM_MOUSEWHEEL = $020A;
            當(dāng)鼠標(biāo)輪子轉(zhuǎn)動(dòng)時(shí)發(fā)送此消息個(gè)當(dāng)前有焦點(diǎn)的控件
            WM_MOUSELAST = $020A;
            WM_PARENTNOTIFY = $0210;
            當(dāng)MDI子窗口被創(chuàng)建或被銷(xiāo)毀,或用戶(hù)按了一下鼠標(biāo)鍵而光標(biāo)在子窗口上時(shí)發(fā)送此消息給它的父窗口
            WM_ENTERMENULOOP = $0211;
            發(fā)送此消息通知應(yīng)用程序的主窗口that已經(jīng)進(jìn)入了菜單循環(huán)模式
            WM_EXITMENULOOP = $0212;
            發(fā)送此消息通知應(yīng)用程序的主窗口that已退出了菜單循環(huán)模式
            WM_NEXTMENU = $0213;
            WM_SIZING = 532;
            當(dāng)用戶(hù)正在調(diào)整窗口大小時(shí)發(fā)送此消息給窗口;通過(guò)此消息應(yīng)用程序可以監(jiān)視窗口大小和位置也可以修改他們
            WM_CAPTURECHANGED = 533;
            發(fā)送此消息 給窗口當(dāng)它失去捕獲的鼠標(biāo)時(shí);
            WM_MOVING = 534;
            當(dāng)用戶(hù)在移動(dòng)窗口時(shí)發(fā)送此消息,通過(guò)此消息應(yīng)用程序可以監(jiān)視窗口大小和位置也可以修改他們;
            WM_POWERBROADCAST = 536;
            此消息發(fā)送給應(yīng)用程序來(lái)通知它有關(guān)電源管理事件;
            WM_DEVICECHANGE = 537;
            當(dāng)設(shè)備的硬件配置改變時(shí)發(fā)送此消息給應(yīng)用程序或設(shè)備驅(qū)動(dòng)程序
            WM_IME_STARTCOMPOSITION = $010D;
            WM_IME_ENDCOMPOSITION = $010E;
            WM_IME_COMPOSITION = $010F;
            WM_IME_KEYLAST = $010F;
            WM_IME_SETCONTEXT = $0281;
            WM_IME_NOTIFY = $0282;
            WM_IME_CONTROL = $0283;
            WM_IME_COMPOSITIONFULL = $0284;
            WM_IME_SELECT = $0285;
            WM_IME_CHAR = $0286;
            WM_IME_REQUEST = $0288;
            WM_IME_KEYDOWN = $0290;
            WM_IME_KEYUP = $0291;
            WM_MDICREATE = $0220;
            應(yīng)用程序發(fā)送此消息給多文檔的客戶(hù)窗口來(lái)創(chuàng)建一個(gè)MDI 子窗口
            WM_MDIDESTROY = $0221;
            應(yīng)用程序發(fā)送此消息給多文檔的客戶(hù)窗口來(lái)關(guān)閉一個(gè)MDI 子窗口
            WM_MDIACTIVATE = $0222;
            應(yīng)用程序發(fā)送此消息給多文檔的客戶(hù)窗口通知客戶(hù)窗口激活另一個(gè)MDI子窗口,當(dāng)客戶(hù)窗口收到此消息后,它發(fā)出WM_MDIACTIVE消息給MDI子窗口(未激活)激活它;
            WM_MDIRESTORE = $0223;
            程序 發(fā)送此消息給MDI客戶(hù)窗口讓子窗口從最大最小化恢復(fù)到原來(lái)大小
            WM_MDINEXT = $0224;
            程序 發(fā)送此消息給MDI客戶(hù)窗口激活下一個(gè)或前一個(gè)窗口
            WM_MDIMAXIMIZE = $0225;
            程序發(fā)送此消息給MDI客戶(hù)窗口來(lái)最大化一個(gè)MDI子窗口;
            WM_MDITILE = $0226;
            程序 發(fā)送此消息給MDI客戶(hù)窗口以平鋪方式重新排列所有MDI子窗口
            WM_MDICASCADE = $0227;
            程序 發(fā)送此消息給MDI客戶(hù)窗口以層疊方式重新排列所有MDI子窗口
            WM_MDIICONARRANGE = $0228;
            程序 發(fā)送此消息給MDI客戶(hù)窗口重新排列所有最小化的MDI子窗口
            WM_MDIGETACTIVE = $0229;
            程序 發(fā)送此消息給MDI客戶(hù)窗口來(lái)找到激活的子窗口的句柄
            WM_MDISETMENU = $0230;
            程序 發(fā)送此消息給MDI客戶(hù)窗口用MDI菜單代替子窗口的菜單
            WM_ENTERSIZEMOVE = $0231;
            WM_EXITSIZEMOVE = $0232;
            WM_DROPFILES = $0233;
            WM_MDIREFRESHMENU = $0234;
            WM_MOUSEHOVER = $02A1;
            WM_MOUSELEAVE = $02A3;
            WM_CUT = $0300;
            程序發(fā)送此消息給一個(gè)編輯框或combobox來(lái)刪除當(dāng)前選擇的文本
            WM_COPY = $0301;
            程序發(fā)送此消息給一個(gè)編輯框或combobox來(lái)復(fù)制當(dāng)前選擇的文本到剪貼板
            WM_PASTE = $0302;
            程序發(fā)送此消息給editcontrol或combobox從剪貼板中得到數(shù)據(jù)
            WM_CLEAR = $0303;
            程序發(fā)送此消息給editcontrol或combobox清除當(dāng)前選擇的內(nèi)容;
            WM_UNDO = $0304;
            程序發(fā)送此消息給editcontrol或combobox撤消最后一次操作
            WM_RENDERFORMAT = $0305;

            WM_RENDERALLFORMATS = $0306;
            WM_DESTROYCLIPBOARD = $0307;
            當(dāng)調(diào)用ENPTYCLIPBOARD函數(shù)時(shí) 發(fā)送此消息給剪貼板的所有者
            WM_DRAWCLIPBOARD = $0308;
            當(dāng)剪貼板的內(nèi)容變化時(shí)發(fā)送此消息給剪貼板觀察鏈的第一個(gè)窗口;它允許用剪貼板觀察窗口來(lái)
            顯示剪貼板的新內(nèi)容;
            WM_PAINTCLIPBOARD = $0309;
            當(dāng)剪貼板包含CF_OWNERDIPLAY格式的數(shù)據(jù)并且剪貼板觀察窗口的客戶(hù)區(qū)需要重畫(huà);
            WM_VSCROLLCLIPBOARD = $030A;
            WM_SIZECLIPBOARD = $030B;
            當(dāng)剪貼板包含CF_OWNERDIPLAY格式的數(shù)據(jù)并且剪貼板觀察窗口的客戶(hù)區(qū)域的大小已經(jīng)改變是此消息通過(guò)剪貼板觀察窗口發(fā)送給剪貼板的所有者;
            WM_ASKCBFORMATNAME = $030C;
            通過(guò)剪貼板觀察窗口發(fā)送此消息給剪貼板的所有者來(lái)請(qǐng)求一個(gè)CF_OWNERDISPLAY格式的剪貼板的名字
            WM_CHANGECBCHAIN = $030D;
            當(dāng)一個(gè)窗口從剪貼板觀察鏈中移去時(shí)發(fā)送此消息給剪貼板觀察鏈的第一個(gè)窗口;
            WM_HSCROLLCLIPBOARD = $030E;
            此消息通過(guò)一個(gè)剪貼板觀察窗口發(fā)送給剪貼板的所有者 ;它發(fā)生在當(dāng)剪貼板包含CFOWNERDISPALY格式的數(shù)據(jù)并且有個(gè)事件在剪貼板觀察窗的水平滾動(dòng)條上;所有者應(yīng)滾動(dòng)剪貼板圖象并更新滾動(dòng)條的值;
            WM_QUERYNEWPALETTE = $030F;
            此消息發(fā)送給將要收到焦點(diǎn)的窗口,此消息能使窗口在收到焦點(diǎn)時(shí)同時(shí)有機(jī)會(huì)實(shí)現(xiàn)他的邏輯調(diào)色板
            WM_PALETTEISCHANGING= $0310;
            當(dāng)一個(gè)應(yīng)用程序正要實(shí)現(xiàn)它的邏輯調(diào)色板時(shí)發(fā)此消息通知所有的應(yīng)用程序
            WM_PALETTECHANGED = $0311;
            此消息在一個(gè)擁有焦點(diǎn)的窗口實(shí)現(xiàn)它的邏輯調(diào)色板后發(fā)送此消息給所有頂級(jí)并重疊的窗口,以此來(lái)改變系統(tǒng)調(diào)色板
            WM_HOTKEY = $0312;
            當(dāng)用戶(hù)按下由REGISTERHOTKEY函數(shù)注冊(cè)的熱鍵時(shí)提交此消息
            WM_PRINT = 791;
            應(yīng)用程序發(fā)送此消息僅當(dāng)WINDOWS或其它應(yīng)用程序發(fā)出一個(gè)請(qǐng)求要求繪制一個(gè)應(yīng)用程序的一部分;
            WM_PRINTCLIENT = 792;
            WM_HANDHELDFIRST = 856;
            WM_HANDHELDLAST = 863;
            WM_PENWINFIRST = $0380;
            WM_PENWINLAST = $038F;
            WM_COALESCE_FIRST = $0390;
            WM_COALESCE_LAST = $039F;
            WM_DDE_FIRST = $03E0;
            WM_DDE_INITIATE = WM_DDE_FIRST + 0;
            一個(gè)DDE客戶(hù)程序提交此消息開(kāi)始一個(gè)與服務(wù)器程序的會(huì)話來(lái)響應(yīng)那個(gè)指定的程序和主題名;
            WM_DDE_TERMINATE = WM_DDE_FIRST + 1;
            一個(gè)DDE應(yīng)用程序(無(wú)論是客戶(hù)還是服務(wù)器)提交此消息來(lái)終止一個(gè)會(huì)話;
            WM_DDE_ADVISE = WM_DDE_FIRST + 2;
            一個(gè)DDE客戶(hù)程序提交此消息給一個(gè)DDE服務(wù)程序來(lái)請(qǐng)求服務(wù)器每當(dāng)數(shù)據(jù)項(xiàng)改變時(shí)更新它
            WM_DDE_UNADVISE = WM_DDE_FIRST + 3;
            一個(gè)DDE客戶(hù)程序通過(guò)此消息通知一個(gè)DDE服務(wù)程序不更新指定的項(xiàng)或一個(gè)特殊的剪貼板格式的項(xiàng)
            WM_DDE_ACK = WM_DDE_FIRST + 4;
            此消息通知一個(gè)DDE(動(dòng)態(tài)數(shù)據(jù)交換)程序已收到并正在處理WM_DDE_POKE, WM_DDE_EXECUTE, WM_DDE_DATA, WM_DDE_ADVISE, WM_DDE_UNADVISE, or WM_DDE_INITIAT消息
            WM_DDE_DATA = WM_DDE_FIRST + 5;
            一個(gè)DDE服務(wù)程序提交此消息給DDE客戶(hù)程序來(lái)傳遞個(gè)一數(shù)據(jù)項(xiàng)給客戶(hù)或通知客戶(hù)的一條可用數(shù)據(jù)項(xiàng)
            WM_DDE_REQUEST = WM_DDE_FIRST + 6;
            一個(gè)DDE客戶(hù)程序提交此消息給一個(gè)DDE服務(wù)程序來(lái)請(qǐng)求一個(gè)數(shù)據(jù)項(xiàng)的值;
            WM_DDE_POKE = WM_DDE_FIRST + 7;
            一個(gè)DDE客戶(hù)程序提交此消息給一個(gè)DDE服務(wù)程序,客戶(hù)使用此消息來(lái)請(qǐng)求服務(wù)器接收一個(gè)未經(jīng)同意的數(shù)據(jù)項(xiàng);服務(wù)器通過(guò)答復(fù)WM_DDE_ACK消息提示是否它接收這個(gè)數(shù)據(jù)項(xiàng);
            WM_DDE_EXECUTE = WM_DDE_FIRST + 8;
            一個(gè)DDE客戶(hù)程序提交此消息給一個(gè)DDE服務(wù)程序來(lái)發(fā)送一個(gè)字符串給服務(wù)器讓它象串行命令一樣被處理,服務(wù)器通過(guò)提交WM_DDE_ACK消息來(lái)作回應(yīng);
            WM_DDE_LAST = WM_DDE_FIRST + 8;
            WM_APP = $8000;
            WM_USER = $0400;
            此消息能幫助應(yīng)用程序自定義私有消息;
            /////////////////////////////////////////////////////////////////////
            通 知消息(Notification message)是指這樣一種消息,一個(gè)窗口內(nèi)的子控件發(fā)生了一些事情,需要通知父窗口。通知消息只適用于標(biāo)準(zhǔn)的窗口控件如按鈕、列表框、組合框、編輯 框,以及Windows 95公共控件如樹(shù)狀視圖、列表視圖等。例如,單擊或雙擊一個(gè)控件、在控件中選擇部分文本、操作控件的滾動(dòng)條都會(huì)產(chǎn)生通知消息。
            按扭
            B N _ C L I C K E D //用戶(hù)單擊了按鈕
            B N _ D I S A B L E //按鈕被禁止
            B N _ D O U B L E C L I C K E D //用戶(hù)雙擊了按鈕
            B N _ H I L I T E //用戶(hù)加亮了按鈕
            B N _ PA I N T按鈕應(yīng)當(dāng)重畫(huà)
            B N _ U N H I L I T E加亮應(yīng)當(dāng)去掉
            組合框
            C B N _ C L O S E U P組合框的列表框被關(guān)閉
            C B N _ D B L C L K用戶(hù)雙擊了一個(gè)字符串
            C B N _ D R O P D O W N組合框的列表框被拉出
            C B N _ E D I T C H A N G E用戶(hù)修改了編輯框中的文本
            C B N _ E D I T U P D AT E編輯框內(nèi)的文本即將更新
            C B N _ E R R S PA C E組合框內(nèi)存不足
            C B N _ K I L L F O C U S組合框失去輸入焦點(diǎn)
            C B N _ S E L C H A N G E在組合框中選擇了一項(xiàng)
            C B N _ S E L E N D C A N C E L用戶(hù)的選擇應(yīng)當(dāng)被取消
            C B N _ S E L E N D O K用戶(hù)的選擇是合法的
            C B N _ S E T F O C U S組合框獲得輸入焦點(diǎn)
            編輯框
            E N _ C H A N G E編輯框中的文本己更新
            E N _ E R R S PA C E編輯框內(nèi)存不足
            E N _ H S C R O L L用戶(hù)點(diǎn)擊了水平滾動(dòng)條
            E N _ K I L L F O C U S編輯框正在失去輸入焦點(diǎn)
            E N _ M A X T E X T插入的內(nèi)容被截?cái)?br>E N _ S E T F O C U S編輯框獲得輸入焦點(diǎn)
            E N _ U P D AT E編輯框中的文本將要更新
            E N _ V S C R O L L用戶(hù)點(diǎn)擊了垂直滾動(dòng)條消息含義
            列表框
            L B N _ D B L C L K用戶(hù)雙擊了一項(xiàng)
            L B N _ E R R S PA C E列表框內(nèi)存不夠
            L B N _ K I L L F O C U S列表框正在失去輸入焦點(diǎn)
            L B N _ S E L C A N C E L選擇被取消
            L B N _ S E L C H A N G E選擇了另一項(xiàng)
            L B N _ S E T F O C U S列表框獲得輸入焦點(diǎn)

            posted @ 2008-08-28 10:29 深邃者 閱讀(182) | 評(píng)論 (0)編輯 收藏

            Window API函數(shù)大全(一)

            1. API之網(wǎng)絡(luò)函數(shù)

            WNetAddConnection 創(chuàng)建同一個(gè)網(wǎng)絡(luò)資源的永久性連接 WNetAddConnection2 創(chuàng)建同一個(gè)網(wǎng)絡(luò)資源的連接 WNetAddConnection3 創(chuàng)建同一個(gè)網(wǎng)絡(luò)資源的連接 WNetCancelConnection 結(jié)束一個(gè)網(wǎng)絡(luò)連接 WNetCancelConnection2 結(jié)束一個(gè)網(wǎng)絡(luò)連接 WNetCloseEnum 結(jié)束一次枚舉操作 WNetConnectionDialog 啟動(dòng)一個(gè)標(biāo)準(zhǔn)對(duì)話框,以便建立同網(wǎng)絡(luò)資源的連接 WNetDisconnectDialog 啟動(dòng)一個(gè)標(biāo)準(zhǔn)對(duì)話框,以便斷開(kāi)同網(wǎng)絡(luò)資源的連接 WNetEnumResource 枚舉網(wǎng)絡(luò)資源 WNetGetConnection 獲取本地或已連接的一個(gè)資源的網(wǎng)絡(luò)名稱(chēng) WNetGetLastError 獲取網(wǎng)絡(luò)錯(cuò)誤的擴(kuò)展錯(cuò)誤信息 WNetGetUniversalName 獲取網(wǎng)絡(luò)中一個(gè)文件的遠(yuǎn)程名稱(chēng)以及/或者UNC(統(tǒng)一命名規(guī)范)名稱(chēng) WNetGetUser 獲取一個(gè)網(wǎng)絡(luò)資源用以連接的名字 WNetOpenEnum 啟動(dòng)對(duì)網(wǎng)絡(luò)資源進(jìn)行枚舉的過(guò)程

            2. API之消息函數(shù)

            BroadcastSystemMessage 將一條系統(tǒng)消息廣播給系統(tǒng)中所有的頂級(jí)窗口 GetMessagePos 取得消息隊(duì)列中上一條消息處理完畢時(shí)的鼠標(biāo)指針屏幕位置 GetMessageTime 取得消息隊(duì)列中上一條消息處理完畢時(shí)的時(shí)間 PostMessage 將一條消息投遞到指定窗口的消息隊(duì)列 PostThreadMessage 將一條消息投遞給應(yīng)用程序 RegisterWindowMessage 獲取分配給一個(gè)字串標(biāo)識(shí)符的消息編號(hào) ReplyMessage 答復(fù)一個(gè)消息 SendMessage 調(diào)用一個(gè)窗口的窗口函數(shù),將一條消息發(fā)給那個(gè)窗口 SendMessageCallback 將一條消息發(fā)給窗口 SendMessageTimeout 向窗口發(fā)送一條消息 SendNotifyMessage 向窗口發(fā)送一條消息

            3. API之文件處理函數(shù)

            CloseHandle 關(guān)閉一個(gè)內(nèi)核對(duì)象。其中包括文件、文件映射、進(jìn)程、線程、安全和同步對(duì)象等 CompareFileTime 對(duì)比兩個(gè)文件的時(shí)間 CopyFile 復(fù)制文件 CreateDirectory 創(chuàng)建一個(gè)新目錄 CreateFile 打開(kāi)和創(chuàng)建文件、管道、郵槽、通信服務(wù)、設(shè)備以及控制臺(tái) CreateFileMapping 創(chuàng)建一個(gè)新的文件映射對(duì)象 DeleteFile 刪除指定文件 DeviceIoControl 對(duì)設(shè)備執(zhí)行指定的操作 DosDateTimeToFileTime 將DOS日期和時(shí)間值轉(zhuǎn)換成一個(gè) win32 FILETIME 值 FileTimeToDosDateTime 將一個(gè) win32 FILETIME 值轉(zhuǎn)換成DOS日期和時(shí)間值 FileTimeToLocalFileTime 將一個(gè)FILETIME結(jié)構(gòu)轉(zhuǎn)換成本地時(shí)間 FileTimeToSystemTime 根據(jù)一個(gè)FILETIME結(jié)構(gòu)的內(nèi)容,裝載一個(gè)SYSTEMTIME結(jié)構(gòu) FindClose 關(guān)閉由FindFirstFile函數(shù)創(chuàng)建的一個(gè)搜索句柄 FindFirstFile 根據(jù)文件名查找文件 FindNextFile 根據(jù)調(diào)用FindFirstFile函數(shù)時(shí)指定的一個(gè)文件名查找下一個(gè)文件 FlushFileBuffers 針對(duì)指定的文件句柄,刷新內(nèi)部文件緩沖區(qū) FlushViewOfFile 將寫(xiě)入文件映射緩沖區(qū)的所有數(shù)據(jù)都刷新到磁盤(pán) GetBinaryType 判斷文件是否可以執(zhí)行 GetCompressedFileSize 判斷一個(gè)壓縮文件在磁盤(pán)上實(shí)際占據(jù)的字節(jié)數(shù) GetCurrentDirectory 在一個(gè)緩沖區(qū)中裝載當(dāng)前目錄 GetDiskFreeSpace 獲取與一個(gè)磁盤(pán)的組織有關(guān)的信息,以及了解剩余空間的容量 GetDiskFreeSpaceEx 獲取與一個(gè)磁盤(pán)的組織以及剩余空間容量有關(guān)的信息 GetDriveType 判斷一個(gè)磁盤(pán)驅(qū)動(dòng)器的類(lèi)型 GetExpandedName 取得一個(gè)壓縮文件的全名 GetFileAttributes 判斷指定文件的屬性 GetFileInformationByHandle 這個(gè)函數(shù)提供了獲取文件信息的一種機(jī)制 GetFileSize 判斷文件長(zhǎng)度 GetFileTime 取得指定文件的時(shí)間信息 GetFileType 在給出文件句柄的前提下,判斷文件類(lèi)型 GetFileVersionInfo 從支持版本標(biāo)記的一個(gè)模塊里獲取文件版本信息 GetFileVersionInfoSize 針對(duì)包含了版本資源的一個(gè)文件,判斷容納文件版本信息需要一個(gè)多大的緩沖區(qū) GetFullPathName 獲取指定文件的完整路徑名 GetLogicalDrives 判斷系統(tǒng)中存在哪些邏輯驅(qū)動(dòng)器字母 GetLogicalDriveStrings 獲取一個(gè)字串,其中包含了當(dāng)前所有邏輯驅(qū)動(dòng)器的根驅(qū)動(dòng)器路徑 GetOverlappedResult 判斷一個(gè)重疊操作當(dāng)前的狀態(tài) GetPrivateProfileInt 為初始化文件(.ini文件)中指定的條目獲取一個(gè)整數(shù)值 GetPrivateProfileSection 獲取指定小節(jié)(在.ini文件中)所有項(xiàng)名和值的一個(gè)列表 GetPrivateProfileString 為初始化文件中指定的條目取得字串 GetProfileInt 取得win.ini初始化文件中指定條目的一個(gè)整數(shù)值 GetProfileSection 獲取指定小節(jié)(在win.ini文件中)所有項(xiàng)名和值的一個(gè)列表 GetProfileString 為win.ini初始化文件中指定的條目取得字串 GetShortPathName 獲取指定文件的短路徑名 GetSystemDirectory 取得Windows系統(tǒng)目錄(即System目錄)的完整路徑名 GetTempFileName 這個(gè)函數(shù)包含了一個(gè)臨時(shí)文件的名字,它可由應(yīng)用程序使用 GetTempPath 獲取為臨時(shí)文件指定的路徑 GetVolumeInformation 獲取與一個(gè)磁盤(pán)卷有關(guān)的信息 GetWindowsDirectory 獲取Windows目錄的完整路徑名 hread 參考lread hwrite 參考lwrite函數(shù) lclose 關(guān)閉指定的文件 lcreat 創(chuàng)建一個(gè)文件 llseek 設(shè)置文件中進(jìn)行讀寫(xiě)的當(dāng)前位置 LockFile 鎖定文件的某一部分,使其不與其他應(yīng)用程序共享 LockFileEx 與LockFile相似,只是它提供了更多的功能 lopen 以二進(jìn)制模式打開(kāi)指定的文件 lread 將文件中的數(shù)據(jù)讀入內(nèi)存緩沖區(qū) lwrite 將數(shù)據(jù)從內(nèi)存緩沖區(qū)寫(xiě)入一個(gè)文件 LZClose 關(guān)閉由LZOpenFile 或 LZInit函數(shù)打開(kāi)的一個(gè)文件 LZCopy 復(fù)制一個(gè)文件 LZInit 這個(gè)函數(shù)用于初始化內(nèi)部緩沖區(qū) LZOpenFile 該函數(shù)能執(zhí)行大量不同的文件處理,而且兼容于壓縮文件 LZRead 將數(shù)據(jù)從文件讀入內(nèi)存緩沖區(qū) LZSeek 設(shè)置一個(gè)文件中進(jìn)行讀寫(xiě)的當(dāng)前位置 MapViewOfFile 將一個(gè)文件映射對(duì)象映射到當(dāng)前應(yīng)用程序的地址空間 MoveFile 移動(dòng)文件 OpenFile 這個(gè)函數(shù)能執(zhí)行大量不同的文件操作 OpenFileMapping 打開(kāi)一個(gè)現(xiàn)成的文件映射對(duì)象 QueryDosDevice 在Windows NT中,DOS設(shè)備名會(huì)映射成NT系統(tǒng)設(shè)備名。該函數(shù)可判斷當(dāng)前的設(shè)備映射情況 ReadFile 從文件中讀出數(shù)據(jù) ReadFileEx 與ReadFile相似,只是它只能用于異步讀操作,并包含了一個(gè)完整的回調(diào) RegCloseKey 關(guān)閉系統(tǒng)注冊(cè)表中的一個(gè)項(xiàng)(或鍵) RegConnectRegistry 訪問(wèn)遠(yuǎn)程系統(tǒng)的部分注冊(cè)表 RegCreateKey 在指定的項(xiàng)下創(chuàng)建或打開(kāi)一個(gè)項(xiàng) RegCreateKeyEx 在指定項(xiàng)下創(chuàng)建新項(xiàng)的更復(fù)雜的方式。在Win32環(huán)境中建議使用這個(gè)函數(shù) RegDeleteKey 刪除現(xiàn)有項(xiàng)下方一個(gè)指定的子項(xiàng) RegDeleteValue 刪除指定項(xiàng)下方的一個(gè)值 RegEnumKey 枚舉指定項(xiàng)的子項(xiàng)。在Win32環(huán)境中應(yīng)使用RegEnumKeyEx RegEnumKeyEx 枚舉指定項(xiàng)下方的子項(xiàng) RegEnumValue 枚舉指定項(xiàng)的值 RegFlushKey 將對(duì)項(xiàng)和它的子項(xiàng)作出的改動(dòng)實(shí)際寫(xiě)入磁盤(pán) RegGetKeySecurity 獲取與一個(gè)注冊(cè)表項(xiàng)有關(guān)的安全信息 RegLoadKey 從以前用RegSaveKey函數(shù)創(chuàng)建的一個(gè)文件里裝載注冊(cè)表信息 RegNotifyChangeKeyValue 注冊(cè)表項(xiàng)或它的任何一個(gè)子項(xiàng)發(fā)生變化時(shí),用這個(gè)函數(shù)提供一種通知機(jī)制 RegOpenKey 打開(kāi)一個(gè)現(xiàn)有的注冊(cè)表項(xiàng) RegOpenKeyEx 打開(kāi)一個(gè)現(xiàn)有的項(xiàng)。在win32下推薦使用這個(gè)函數(shù) RegQueryInfoKey 獲取與一個(gè)項(xiàng)有關(guān)的信息 RegQueryValue 取得指定項(xiàng)或子項(xiàng)的默認(rèn)(未命名)值 RegQueryValueEx 獲取一個(gè)項(xiàng)的設(shè)置值 RegReplaceKey 用一個(gè)磁盤(pán)文件保存的信息替換注冊(cè)表信息;并創(chuàng)建一個(gè)備份,在其中包含當(dāng)前注冊(cè)表信息 RegRestoreKey 從一個(gè)磁盤(pán)文件恢復(fù)注冊(cè)表信息 RegSaveKey 將一個(gè)項(xiàng)以及它的所有子項(xiàng)都保存到一個(gè)磁盤(pán)文件 RegSetKeySecurity 設(shè)置指定項(xiàng)的安全特性 RegSetValue 設(shè)置指定項(xiàng)或子項(xiàng)的默認(rèn)值 RegSetValueEx 設(shè)置指定項(xiàng)的值 RegUnLoadKey 卸載指定的項(xiàng)以及它的所有子項(xiàng) RemoveDirectory 刪除指定目錄 SearchPath 查找指定文件 SetCurrentDirectory 設(shè)置當(dāng)前目錄 SetEndOfFile 針對(duì)一個(gè)打開(kāi)的文件,將當(dāng)前文件位置設(shè)為文件末尾 SetFileAttributes 設(shè)置文件屬性 SetFilePointer 在一個(gè)文件中設(shè)置當(dāng)前的讀寫(xiě)位置 SetFileTime 設(shè)置文件的創(chuàng)建、訪問(wèn)及上次修改時(shí)間 SetHandleCount 這個(gè)函數(shù)不必在win32下使用;即使使用,也不會(huì)有任何效果 SetVolumeLabel 設(shè)置一個(gè)磁盤(pán)的卷標(biāo)(Label) SystemTimeToFileTime 根據(jù)一個(gè)FILETIME結(jié)構(gòu)的內(nèi)容,載入一個(gè)SYSTEMTIME結(jié)構(gòu) UnlockFile 解除對(duì)一個(gè)文件的鎖定 UnlockFileEx 解除對(duì)一個(gè)文件的鎖定 UnmapViewOfFile 在當(dāng)前應(yīng)用程序的內(nèi)存地址空間解除對(duì)一個(gè)文件映射對(duì)象的映射 VerFindFile 用這個(gè)函數(shù)決定一個(gè)文件應(yīng)安裝到哪里 VerInstallFile 用這個(gè)函數(shù)安裝一個(gè)文件 VerLanguageName 這個(gè)函數(shù)能根據(jù)16位語(yǔ)言代碼獲取一種語(yǔ)言的名稱(chēng) VerQueryValue 這個(gè)函數(shù)用于從版本資源中獲取信息 WriteFile 將數(shù)據(jù)寫(xiě)入一個(gè)文件 WriteFileEx 與WriteFile類(lèi)似,只是它只能用于異步寫(xiě)操作,并包括了一個(gè)完整的回調(diào) WritePrivateProfileSection 為一個(gè)初始化文件(.ini)中指定的小節(jié)設(shè)置所有項(xiàng)名和值 WritePrivateProfileString 在初始化文件指定小節(jié)內(nèi)設(shè)置一個(gè)字串 WriteProfileSection 為Win.ini初始化文件中一個(gè)指定的小節(jié)設(shè)置所有項(xiàng)名和值 WriteProfileString 在Win.ini初始化文件指定小節(jié)內(nèi)設(shè)置一個(gè)字串

            4. API之打印函數(shù) AbortDoc 取消一份文檔的打印 AbortPrinter 刪除與一臺(tái)打印機(jī)關(guān)聯(lián)在一起的緩沖文件 AddForm 為打印機(jī)的表單列表添加一個(gè)新表單 AddJob 用于獲取一個(gè)有效的路徑名,以便用它為作業(yè)創(chuàng)建一個(gè)后臺(tái)打印文件。它也會(huì)為作業(yè)分配一個(gè)作業(yè)編號(hào) AddMonitor 為系統(tǒng)添加一個(gè)打印機(jī)監(jiān)視器 AddPort 啟動(dòng)“添加端口”對(duì)話框,允許用戶(hù)在系統(tǒng)可用端口列表中加入一個(gè)新端口 AddPrinter 在系統(tǒng)中添加一臺(tái)新打印機(jī) AddPrinterConnection 連接指定的打印機(jī) AddPrinterDriver 為指定的系統(tǒng)添加一個(gè)打印驅(qū)動(dòng)程序 AddPrintProcessor 為指定的系統(tǒng)添加一個(gè)打印處理器 AddPrintProvidor 為系統(tǒng)添加一個(gè)打印供應(yīng)商 AdvancedDocumentProperties 啟動(dòng)打印機(jī)文檔設(shè)置對(duì)話框 ClosePrinter 關(guān)閉一個(gè)打開(kāi)的打印機(jī)對(duì)象 ConfigurePort 針對(duì)指定的端口,啟動(dòng)一個(gè)端口配置對(duì)話框 ConnectToPrinterDlg 啟動(dòng)連接打印機(jī)對(duì)話框,用它同訪問(wèn)網(wǎng)絡(luò)的打印機(jī)連接 DeleteForm 從打印機(jī)可用表單列表中刪除一個(gè)表單 DeleteMonitor 刪除指定的打印監(jiān)視器 DeletePort 啟動(dòng)“刪除端口”對(duì)話框,允許用戶(hù)從當(dāng)前系統(tǒng)刪除一個(gè)端口 DeletePrinter 將指定的打印機(jī)標(biāo)志為從系統(tǒng)中刪除 DeletePrinterConnection 刪除與指定打印機(jī)的連接 DeletePrinterDriver 從系統(tǒng)刪除一個(gè)打印機(jī)驅(qū)動(dòng)程序 DeletePrintProcessor 從指定系統(tǒng)刪除一個(gè)打印處理器 DeletePrintProvidor 從系統(tǒng)中刪除一個(gè)打印供應(yīng)商 DeviceCapabilities 利用這個(gè)函數(shù)可獲得與一個(gè)設(shè)備的能力有關(guān)的信息 DocumentProperties 打印機(jī)配置控制函數(shù) EndDocAPI 結(jié)束一個(gè)成功的打印作業(yè) EndDocPrinter 在后臺(tái)打印程序的級(jí)別指定一個(gè)文檔的結(jié)束 EndPage 用這個(gè)函數(shù)完成一個(gè)頁(yè)面的打印,并準(zhǔn)備設(shè)備場(chǎng)景,以便打印下一個(gè)頁(yè) EndPagePrinter 指定一個(gè)頁(yè)在打印作業(yè)中的結(jié)尾 EnumForms 枚舉一臺(tái)打印機(jī)可用的表單 EnumJobs 枚舉打印隊(duì)列中的作業(yè) EnumMonitors 枚舉可用的打印監(jiān)視器 EnumPorts 枚舉一個(gè)系統(tǒng)可用的端口 EnumPrinterDrivers 枚舉指定系統(tǒng)中已安裝的打印機(jī)驅(qū)動(dòng)程序 EnumPrinters 枚舉系統(tǒng)中安裝的打印機(jī) EnumPrintProcessorDatatypes 枚舉由一個(gè)打印處理器支持的數(shù)據(jù)類(lèi)型 EnumPrintProcessors 枚舉系統(tǒng)中可用的打印處理器 Escape 設(shè)備控制函數(shù) FindClosePrinterChangeNotification 關(guān)閉用FindFirstPrinterChangeNotification函數(shù)獲取的一個(gè)打印機(jī)通告對(duì)象 FindFirstPrinterChangeNotification 創(chuàng)建一個(gè)新的改變通告對(duì)象,以便我們注意打印機(jī)狀態(tài)的各種變化 FindNextPrinterChangeNotification 用這個(gè)函數(shù)判斷觸發(fā)一次打印機(jī)改變通告信號(hào)的原因 FreePrinterNotifyInfo 釋放由FindNextPrinterChangeNotification函數(shù)分配的一個(gè)緩沖區(qū) GetForm 取得與指定表單有關(guān)的信息 GetJob 獲取與指定作業(yè)有關(guān)的信息 GetPrinter 取得與指定打印機(jī)有關(guān)的信息 GetPrinterData 為打印機(jī)設(shè)置注冊(cè)表配置信息 GetPrinterDriver 針對(duì)指定的打印機(jī),獲取與打印機(jī)驅(qū)動(dòng)程序有關(guān)的信息 GetPrinterDriverDirectory 判斷指定系統(tǒng)中包含了打印機(jī)驅(qū)動(dòng)程序的目錄是什么 GetPrintProcessorDirectory 判斷指定系統(tǒng)中包含了打印機(jī)處理器驅(qū)動(dòng)程序及文件的目錄 OpenPrinter 打開(kāi)指定的打印機(jī),并獲取打印機(jī)的句柄 PrinterMessageBox 在擁有指定打印作業(yè)的系統(tǒng)上顯示一個(gè)打印機(jī)出錯(cuò)消息框 PrinterProperties 啟動(dòng)打印機(jī)屬性對(duì)話框,以便對(duì)打印機(jī)進(jìn)行配置 ReadPrinter 從打印機(jī)讀入數(shù)據(jù) ResetDC 重設(shè)一個(gè)設(shè)備場(chǎng)景 ResetPrinter 改變指定打印機(jī)的默認(rèn)數(shù)據(jù)類(lèi)型及文檔設(shè)置 ScheduleJob 提交一個(gè)要打印的作業(yè) SetAbortProc 為Windows指定取消函數(shù)的地址 SetForm 為指定的表單設(shè)置信息 SetJob 對(duì)一個(gè)打印作業(yè)的狀態(tài)進(jìn)行控制 SetPrinter 對(duì)一臺(tái)打印機(jī)的狀態(tài)進(jìn)行控制 SetPrinterData 設(shè)置打印機(jī)的注冊(cè)表配置信息 StartDoc 開(kāi)始一個(gè)打印作業(yè) StartDocPrinter 在后臺(tái)打印的級(jí)別啟動(dòng)一個(gè)新文檔 StartPage 打印一個(gè)新頁(yè)前要先調(diào)用這個(gè)函數(shù) StartPagePrinter 在打印作業(yè)中指定一個(gè)新頁(yè)的開(kāi)始 WritePrinter 將發(fā)送目錄中的數(shù)據(jù)寫(xiě)入打印機(jī)

            5. API之文本和字體函數(shù)

            AddFontResource 在Windows系統(tǒng)中添加一種字體資源 CreateFont 用指定的屬性創(chuàng)建一種邏輯字體 CreateFontIndirect 用指定的屬性創(chuàng)建一種邏輯字體 CreateScalableFontResource 為一種TureType字體創(chuàng)建一個(gè)資源文件,以便能用API函數(shù)AddFontResource將其加入Windows系統(tǒng) DrawText 將文本描繪到指定的矩形中 DrawTextEx 與DrawText相似,只是加入了更多的功能 EnumFontFamilies 列舉指定設(shè)備可用的字體 EnumFontFamiliesEx 列舉指定設(shè)備可用的字體 EnumFonts 列舉指定設(shè)備可用的字體 ExtTextOut 經(jīng)過(guò)擴(kuò)展的文本描繪函數(shù)。也請(qǐng)參考SetTextAlign函數(shù) GetAspectRatioFilterEx 用SetMapperFlags要求Windows只選擇與設(shè)備當(dāng)前縱橫比相符的光柵字體時(shí),本函數(shù)可判斷縱橫比大小 GetCharABCWidths 判斷TureType字體中一個(gè)或多個(gè)字符的A-B-C大小 GetCharABCWidthsFloat 查詢(xún)一種字體中一個(gè)或多個(gè)字符的A-B-C尺寸 GetCharacterPlacement 該函數(shù)用于了解如何用一個(gè)給定的字符顯示一個(gè)字串 GetCharWidth 調(diào)查字體中一個(gè)或多個(gè)字符的寬度 GetFontData 接收一種可縮放字體文件的數(shù)據(jù) GetFontLanguageInfo 返回目前選入指定設(shè)備場(chǎng)景中的字體的信息 GetGlyphOutline 取得TureType字體中構(gòu)成一個(gè)字符的曲線信息 GetKerningPairs 取得指定字體的字距信息 GetOutlineTextMetrics 接收與TureType字體內(nèi)部特征有關(guān)的詳細(xì)信息 GetRasterizerCaps 了解系統(tǒng)是否有能力支持可縮放的字體 GetTabbedTextExtent 判斷一個(gè)字串占據(jù)的范圍,同時(shí)考慮制表站擴(kuò)充的因素 GetTextAlign 接收一個(gè)設(shè)備場(chǎng)景當(dāng)前的文本對(duì)齊標(biāo)志 GetTextCharacterExtra 判斷額外字符間距的當(dāng)前值 GetTextCharset 接收當(dāng)前選入指定設(shè)備場(chǎng)景的字體的字符集標(biāo)識(shí)符 GetTextCharsetInfo 獲取與當(dāng)前選定字體的字符集有關(guān)的詳細(xì)信息 GetTextColor 判斷當(dāng)前字體顏色。通常也稱(chēng)為“前景色” GetTextExtentExPoint 判斷要填入指定區(qū)域的字符數(shù)量。也用一個(gè)數(shù)組裝載每個(gè)字符的范圍信息 GetTextExtentPoint 判斷一個(gè)字串的大小(范圍) GetTextFace 獲取一種字體的字樣名 GetTextMetrics 獲取與選入一種設(shè)備場(chǎng)景的物理字體有關(guān)的信息 GrayString 描繪一個(gè)以灰色顯示的字串。通常由Windows用于標(biāo)識(shí)禁止?fàn)顟B(tài) PolyTextOut 描繪一系列字串 RemoveFontResource 從Windows系統(tǒng)中刪除一種字體資源 SetMapperFlags Windows對(duì)字體進(jìn)行映射時(shí),可用該函數(shù)選擇與目標(biāo)設(shè)備的縱橫比相符的光柵字體 SetTextAlign 設(shè)置文本對(duì)齊方式,并指定在文本輸出過(guò)程中使用設(shè)備場(chǎng)景的當(dāng)前位置 SetTextCharacterExtra 描繪文本的時(shí)候,指定要在字符間插入的額外間距 SetTextColor 設(shè)置當(dāng)前文本顏色。這種顏色也稱(chēng)為“前景色” SetTextJustification 通過(guò)指定一個(gè)文本行應(yīng)占據(jù)的額外空間,可用這個(gè)函數(shù)對(duì)文本進(jìn)行兩端對(duì)齊處理 TabbedTextOut 支持制表站的一個(gè)文本描繪函數(shù) TextOut 文本繪圖函數(shù)

            6. API之菜單函數(shù)

            AppendMenu 在指定的菜單里添加一個(gè)菜單項(xiàng) CheckMenuItem 復(fù)選或撤消復(fù)選指定的菜單條目 CheckMenuRadioItem 指定一個(gè)菜單條目被復(fù)選成“單選”項(xiàng)目 CreateMenu 創(chuàng)建新菜單 CreatePopupMenu 創(chuàng)建一個(gè)空的彈出式菜單 DeleteMenu 刪除指定的菜單條目 DestroyMenu 刪除指定的菜單 DrawMenuBar 為指定的窗口重畫(huà)菜單 EnableMenuItem 允許或禁止指定的菜單條目 GetMenu 取得窗口中一個(gè)菜單的句柄 GetMenuCheckMarkDimensions 返回一個(gè)菜單復(fù)選符的大小 GetMenuContextHelpId 取得一個(gè)菜單的幫助場(chǎng)景ID GetMenuDefaultItem 判斷菜單中的哪個(gè)條目是默認(rèn)條目 GetMenuItemCount 返回菜單中條目(菜單項(xiàng))的數(shù)量 GetMenuItemID 返回位于菜單中指定位置處的條目的菜單ID GetMenuItemInfo 取得(接收)與一個(gè)菜單條目有關(guān)的特定信息 GetMenuItemRect 在一個(gè)矩形中裝載指定菜單條目的屏幕坐標(biāo)信息 GetMenuState 取得與指定菜單條目狀態(tài)有關(guān)的信息 GetMenuString 取得指定菜單條目的字串 GetSubMenu 取得一個(gè)彈出式菜單的句柄,它位于菜單中指定的位置 GetSystemMenu 取得指定窗口的系統(tǒng)菜單的句柄 HiliteMenuItem 控制頂級(jí)菜單條目的加亮顯示狀態(tài) InsertMenu 在菜單的指定位置處插入一個(gè)菜單條目,并根據(jù)需要將其他條目向下移動(dòng) InsertMenuItem 插入一個(gè)新菜單條目 IsMenu 判斷指定的句柄是否為一個(gè)菜單的句柄 LoadMenu 從指定的模塊或應(yīng)用程序?qū)嵗休d入一個(gè)菜單 LoadMenuIndirect 載入一個(gè)菜單 MenuItemFromPoint 判斷哪個(gè)菜單條目包含了屏幕上一個(gè)指定的點(diǎn) ModifyMenu 改變菜單條目 RemoveMenu 刪除指定的菜單條目 SetMenu 設(shè)置窗口菜單 SetMenuContextHelpId 設(shè)置一個(gè)菜單的幫助場(chǎng)景ID SetMenuDefaultItem 將一個(gè)菜單條目設(shè)為默認(rèn)條目 SetMenuItemBitmaps 設(shè)置一幅特定位圖,令其在指定的菜單條目中使用,代替標(biāo)準(zhǔn)的復(fù)選符號(hào)(√) SetMenuItemInfo 為一個(gè)菜單條目設(shè)置指定的信息 TrackPopupMenu 在屏幕的任意地方顯示一個(gè)彈出式菜單 TrackPopupMenuEx 與TrackPopupMenu相似,只是它提供了額外的功能

            posted @ 2008-08-28 10:28 深邃者 閱讀(254) | 評(píng)論 (0)編輯 收藏

            windows消息說(shuō)明

            WM_PAINT = $000F;
            要求一個(gè)窗口重畫(huà)自己
            WM_CLOSE = $0010;
            當(dāng)一個(gè)窗口或應(yīng)用程序要關(guān)閉時(shí)發(fā)送一個(gè)信號(hào)
            WM_QUERYENDSESSION = $0011;
            當(dāng)用戶(hù)選擇結(jié)束對(duì)話框或程序自己調(diào)用ExitWindows函數(shù)
            WM_QUIT = $0012;
            用來(lái)結(jié)束程序運(yùn)行或當(dāng)程序調(diào)用postquitmessage函數(shù)
            WM_QUERYOPEN = $0013;
            當(dāng)用戶(hù)窗口恢復(fù)以前的大小位置時(shí),把此消息發(fā)送給某個(gè)圖標(biāo)
            WM_ERASEBKGND = $0014;
            當(dāng)窗口背景必須被擦除時(shí)(例在窗口改變大小時(shí))
            WM_SYSCOLORCHANGE = $0015;
            當(dāng)系統(tǒng)顏色改變時(shí),發(fā)送此消息給所有頂級(jí)窗口
            WM_ENDSESSION = $0016;
            當(dāng)系統(tǒng)進(jìn)程發(fā)出WM_QUERYENDSESSION消息后,此消息發(fā)送給應(yīng)用程序,
            通知它對(duì)話是否結(jié)束
            WM_SYSTEMERROR = $0017;
            WM_SHOWWINDOW = $0018;
            當(dāng)隱藏或顯示窗口是發(fā)送此消息給這個(gè)窗口
            WM_ACTIVATEAPP = $001C;
            發(fā)此消息給應(yīng)用程序哪個(gè)窗口是激活的,哪個(gè)是非激活的;
            WM_FONTCHANGE = $001D;
            當(dāng)系統(tǒng)的字體資源庫(kù)變化時(shí)發(fā)送此消息給所有頂級(jí)窗口
            WM_TIMECHANGE = $001E;
            當(dāng)系統(tǒng)的時(shí)間變化時(shí)發(fā)送此消息給所有頂級(jí)窗口
            WM_CANCELMODE = $001F;
            發(fā)送此消息來(lái)取消某種正在進(jìn)行的摸態(tài)(操作)
            WM_SETCURSOR = $0020;
            如果鼠標(biāo)引起光標(biāo)在某個(gè)窗口中移動(dòng)且鼠標(biāo)輸入沒(méi)有被捕獲時(shí),就發(fā)消息給某個(gè)窗口
            WM_MOUSEACTIVATE = $0021;
            當(dāng)光標(biāo)在某個(gè)非激活的窗口中而用戶(hù)正按著鼠標(biāo)的某個(gè)鍵發(fā)送此消息給當(dāng)前窗口
            WM_CHILDACTIVATE = $0022;
            發(fā)送此消息給MDI子窗口當(dāng)用戶(hù)點(diǎn)擊此窗口的標(biāo)題欄,或當(dāng)窗口被激活,移動(dòng),改變大小

            WM_QUEUESYNC = $0023;
            此消息由基于計(jì)算機(jī)的訓(xùn)練程序發(fā)送,通過(guò)WH_JOURNALPALYBACK的hook程序
            分離出用戶(hù)輸入消息
            WM_GETMINMAXINFO = $0024;
            此消息發(fā)送給窗口當(dāng)它將要改變大小或位置;
            WM_PAINTICON = $0026;
            發(fā)送給最小化窗口當(dāng)它圖標(biāo)將要被重畫(huà)
            WM_ICONERASEBKGND = $0027;
            此消息發(fā)送給某個(gè)最小化窗口,僅當(dāng)它在畫(huà)圖標(biāo)前它的背景必須被重畫(huà)
            WM_NEXTDLGCTL = $0028;
            發(fā)送此消息給一個(gè)對(duì)話框程序去更改焦點(diǎn)位置
            WM_SPOOLERSTATUS = $002A;
            每當(dāng)打印管理列隊(duì)增加或減少一條作業(yè)時(shí)發(fā)出此消息
            WM_DRAWITEM = $002B;
            當(dāng)button,combobox,listbox,menu的可視外觀改變時(shí)發(fā)送
            此消息給這些空件的所有者

            WM_MEASUREITEM = $002C;
            當(dāng)button, combo box, list box, list view control, or menu item 被創(chuàng)建時(shí)
            發(fā)送此消息給控件的所有者
            WM_DELETEITEM = $002D;
            當(dāng)the list box 或 combo box 被銷(xiāo)毀 或 當(dāng) 某些項(xiàng)被刪除通過(guò)LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT 消息
            WM_VKEYTOITEM = $002E;
            此消息有一個(gè)LBS_WANTKEYBOARDINPUT風(fēng)格的發(fā)出給它的所有者來(lái)響應(yīng)WM_KEYDOWN消息
            WM_CHARTOITEM = $002F;
            此消息由一個(gè)LBS_WANTKEYBOARDINPUT風(fēng)格的列表框發(fā)送給他的所有者來(lái)響應(yīng)WM_CHAR消息

            posted @ 2008-07-22 18:16 深邃者 閱讀(142) | 評(píng)論 (0)編輯 收藏

            MFC共享DLL模塊狀態(tài)的切換AFX_MODULE_STATE

            在DLL中使用資源(一)

            yuwei - 轉(zhuǎn)載 (2004-12-10 14:02:00)  .Net控件開(kāi)發(fā) ActiveX/COM開(kāi)發(fā) CLX/VCL開(kāi)發(fā) Java組件開(kāi)發(fā) VC/MFC 控件使用經(jīng)驗(yàn)談 DHtml/Script 控件開(kāi)發(fā)基礎(chǔ) 數(shù)據(jù)庫(kù) 編程規(guī)范 單元測(cè)試 可重用軟件技術(shù)理論 其 它
             
             
             
               

            在DLL中使用資源(一)
            現(xiàn)在最常看見(jiàn)的關(guān)于DLL的問(wèn)題就是如何在DLL中使用對(duì)話框,這是一個(gè)很普遍的關(guān)于如何在DLL中使用資源的問(wèn)題。這里我們從Win32 DLL和MFC DLL兩個(gè)方面來(lái)分析并解決這個(gè)問(wèn)題。

            1.Win32 DLL
            在Win32 DLL中使用對(duì)話框很簡(jiǎn)單,你只需要在你的DLL中添加對(duì)話框資源,而且可以在對(duì)話框上面設(shè)置你所需要的控件。然后使用DialogBox或者CreateDialog這兩個(gè)函數(shù)(或相同作用的其它函數(shù))來(lái)創(chuàng)建對(duì)話框,并定義你自己的對(duì)話框回調(diào)函數(shù)處理對(duì)話框收到的消息。下面通過(guò)一個(gè)具體實(shí)例來(lái)學(xué)習(xí)如何在Win32 DLL中使用對(duì)話框,可以按照以下步驟來(lái)完成這個(gè)例子:


            1)在VC菜單中File->New新建一個(gè)命名為UseDlg的Win32 Dynamic-Link Library工程,下一步選擇A simple DLL project。


            2)在VC菜單中Insert->Resource添加一個(gè)ID為IDD_DLG_SHOW的Dialog資源,將此Dialog上的Cancel按鈕去掉,僅保留OK按鈕。再添加一個(gè)ID為IDD_ABOUTBOX的對(duì)話框,其Caption為About。保存此資源,將資源文件命名為UseDlg.rc。并將resource.h和UseDlg.rc加入到工程里面。


            3)在UseDlg.app中包含resource.h,并添加如下代碼:


            HINSTANCE hinst = NULL;

            HWND hwndDLG = NULL;


            BOOL CALLBACK DlgProc(HWND hDlg, UINT message,

            WPARAM wParam, LPARAM lParam);

            BOOL CALLBACK AboutProc(HWND hDlg, UINT message,

            WPARAM wParam, LPARAM lParam);

            extern "C" __declspec(dllexport) void ShowDlg();


            BOOL APIENTRY DllMain( HANDLE hModule,

            DWORD ul_reason_for_call,

            LPVOID lpReserved

            )

            {

            switch(ul_reason_for_call)

            {

            case DLL_PROCESS_ATTACH:

            hinst = (HINSTANCE)hModule;

            case DLL_PROCESS_DETACH:

            break;

            }

            return TRUE;

            }


            extern "C" __declspec(dllexport) void ShowDlg()

            {

            hwndDLG = CreateDialog(hinst,MAKEINTRESOURCE(IDD_DLG_SHOW),

            NULL,(DLGPROC)DlgProc);

            ShowWindow(hwndDLG, SW_SHOW);

            }


            BOOL CALLBACK DlgProc(HWND hDlg, UINT message,

            WPARAM wParam, LPARAM lParam)

            {

            switch(message)

            {

            case WM_INITDIALOG:

            return TRUE;


            case WM_COMMAND:

            if(LOWORD(wParam)==IDOK)

            DialogBox(hinst,MAKEINTRESOURCE(IDD_ABOUTBOX),

            hDlg,(DLGPROC)AboutProc);

            return TRUE;

            case WM_CLOSE:

            DestroyWindow(hDlg);

            hwndDLG = NULL;

            return TRUE;

            }

            return FALSE;

            }


            BOOL CALLBACK AboutProc(HWND hDlg, UINT message,

            WPARAM wParam, LPARAM lParam)

            {

            switch(message)

            {

            case WM_CLOSE:

            EndDialog(hDlg,NULL);

            hwndDLG = NULL;

            return TRUE;

            }

            return FALSE;

            }


            4)編譯生成UseDlg.dll和UseDlg.lib。


            接下來(lái)我們建立調(diào)用此DLL的應(yīng)用程序,其步驟如下:



            1)在VC菜單中File->New新建一個(gè)命名為Use的MFC AppWizard(exe)工程,下一步選擇Dialog Based之后點(diǎn)擊Finish按鈕。


            2)在主對(duì)話框上面添加一個(gè)按鈕,之后雙擊此按鈕,會(huì)彈出Add Member Function的對(duì)話框,直接點(diǎn)擊OK進(jìn)入void CUseDlg::OnButton1()函數(shù)。并在此函數(shù)內(nèi)添加一個(gè)函數(shù)調(diào)用:ShowDlg();。


            3)緊跟在#include語(yǔ)句后面加上如下代碼:


            extern "C" __declspec(dllexport) void ShowDlg();

            #pragma comment(lib,"debug/UseDlg")


            4)將上面UseDlg工程中生成的UseDlg.dll和UseDlg.lib兩個(gè)文件復(fù)制到Use工程的Debug目錄內(nèi)。


            5)編譯生成Use.exe。


            運(yùn)行Use.exe,點(diǎn)擊Button1按鈕,可以看到一個(gè)名稱(chēng)為Dialog的非模態(tài)對(duì)話框彈出。點(diǎn)擊上面的按鈕,可以彈出模態(tài)對(duì)話框About。運(yùn)行成功。


            讓我們來(lái)回顧一下在Win32 DLL中使用對(duì)話框的過(guò)程。


            在DLL中,我們定義了兩個(gè)對(duì)話框資源:IDD_DLG_SHOW和IDD_ABOUTBOX,并且導(dǎo)出了函數(shù)ShowDlg。在函數(shù)ShowDlg之中使用CreateDialog函數(shù)創(chuàng)建了非模態(tài)對(duì)話框IDD_DLG_SHOW,并指定了該對(duì)話框的回調(diào)函數(shù)DlgProc。在DlgProc之中處理了WM_INITDIALOG、WM_COMMAND和WM_CLOSE消息,以響應(yīng)用戶(hù)對(duì)對(duì)話框所做的動(dòng)作。在處理按鈕動(dòng)作的時(shí)候,使用DialogBox函數(shù)創(chuàng)建IDD_ABOUTBOX這個(gè)模態(tài)對(duì)話框,指定其回調(diào)函數(shù)為AboutProc,并且在AboutProc中處理其相應(yīng)消息。


            在EXE中,我們使用隱式鏈接的方法來(lái)調(diào)用DLL,并使用DLL中導(dǎo)出的ShowDlg函數(shù)來(lái)調(diào)用DLL中的對(duì)話框。


            在Win32 DLL中使用對(duì)話框就是這么簡(jiǎn)單,下面讓我們來(lái)看一下在MFC DLL中如何使用對(duì)話框。

            2.MFC DLL
            在MFC DLL中使用對(duì)話框不像Win32 DLL中那么簡(jiǎn)單,主要是因?yàn)镸FC程序中存在一個(gè)模塊狀態(tài)(Module State)的問(wèn)題,也就是資源重復(fù)的問(wèn)題。(此處的術(shù)語(yǔ)模塊是指一個(gè)可執(zhí)行程序,或指其操作不依賴(lài)于應(yīng)用程序的其余部分但使用MFC運(yùn)行庫(kù)的共享副本的一個(gè)DLL(或一組DLL)。我們所創(chuàng)建的MFC DLL就是這種模塊的一個(gè)典型實(shí)例。)


            在每個(gè)模塊(EXE或DLL)中,都存在一種全局的狀態(tài)數(shù)據(jù),MFC依靠這種全局的狀態(tài)數(shù)據(jù)來(lái)區(qū)分不同的模塊,以執(zhí)行正確的操作。這種數(shù)據(jù)包括:Windows實(shí)例句柄(用于加載資源),指向應(yīng)用程序當(dāng)前的CWinApp和CWinThread對(duì)象的指針,OLE模塊引用計(jì)數(shù),以及維護(hù)Windows對(duì)象句柄與相應(yīng)的MFC對(duì)象實(shí)例之間連接的各種映射等。但當(dāng)應(yīng)用程序使用多個(gè)模塊時(shí),每個(gè)模塊的狀態(tài)數(shù)據(jù)不是應(yīng)用程序范圍的。相反,每個(gè)模塊具有自已的MFC狀態(tài)數(shù)據(jù)的私有副本。這種全局的狀態(tài)數(shù)據(jù)就叫做MFC模塊狀態(tài)。


            模塊的狀態(tài)數(shù)據(jù)包含在結(jié)構(gòu)中,并且總是可以通過(guò)指向該結(jié)構(gòu)的指針使用。當(dāng)代碼在執(zhí)行時(shí)進(jìn)入了某一個(gè)模塊時(shí),只有此模塊的狀態(tài)為“當(dāng)前”或“有效”狀態(tài)時(shí),MFC才能正確的區(qū)分此模塊并執(zhí)行正確的操作。


            例如,MFC應(yīng)用程序可以使用下面代碼從資源文件中加載字符串:


            CString str;

            str.LoadString(IDS_MYSTRING);


            使用這種代碼非常方便,但它掩蓋了這樣一個(gè)事實(shí):即此程序中IDS_MYSTRING可能不是唯一的標(biāo)識(shí)符。一個(gè)程序可以加載多個(gè)DLL,某些DLL可能也用IDS_MYSTRING標(biāo)識(shí)符定義了一個(gè)資源。MFC怎樣知道應(yīng)該加載哪個(gè)資源呢?MFC使用當(dāng)前模塊狀態(tài)查找資源句柄。如果當(dāng)前模塊不是我們要使用的正確模塊,那么就會(huì)產(chǎn)生不正確的調(diào)用或者錯(cuò)誤。



            按照MFC庫(kù)的鏈接方法,一個(gè)MFC DLL有兩種使用MFC庫(kù)的方法:靜態(tài)鏈接到MFC的DLL和動(dòng)態(tài)鏈接到MFC的DLL。下面我們就按照這兩種類(lèi)型的MFC DLL來(lái)介紹如何切換當(dāng)前模塊狀態(tài)以正確的在MFC DLL中使用資源。

            1、靜態(tài)鏈接到MFC的DLL

            靜態(tài)鏈接到MFC的規(guī)則DLL與MFC庫(kù)靜態(tài)鏈接,則此時(shí)MFC庫(kù)不能共享,所以MFC總是使用它所鏈接的DLL的模塊狀態(tài)。這樣也就不存在管理模塊狀態(tài)的問(wèn)題。但使用這種方法的缺點(diǎn)是DLL程序?qū)?huì)變大,而且會(huì)在程序中留下重復(fù)代碼。下面給出的例子驗(yàn)證了這一點(diǎn)。本例可以按照以下步驟來(lái)完成:


            1)在VC菜單中File->New新建一個(gè)命名為DLLStatic的MFC AppWizard的工程,下一步選擇Regular DLL with MFC statically linked。


            2)在工程中添加一個(gè)對(duì)話框資源,其ID為:IDD_ABOUTBOX。并在resource.h之中將IDD_ABOUTBOX 的數(shù)值改為100。


            3)在DLLStatic.cpp中定義如下函數(shù):


            void ShowDlg()

            {

            CDialog dlg(IDD_ABOUTBOX);

            dlg.DoModal();

            }


            4)在DLLStatic.def文件中的EXPORTS語(yǔ)句中添加一行:ShowDlg,以導(dǎo)出ShowDlg函數(shù)。


            5)編譯生成DLLStatic.dll和DLLStatic.lib。


            繼續(xù)使用上一節(jié)中的Use工程,將前面生成的DLLStatic.dll和DLLStatic.lib兩個(gè)文件復(fù)制到工程的Debug目錄內(nèi),并將


            extern "C" __declspec(dllexport) void ShowDlg();

            #pragma comment(lib,"debug/UseDlg")


            這兩行改為:


            void ShowDlg();

            #pragma comment(lib,"debug/DLLStatic")


            編譯并運(yùn)行Use.exe。點(diǎn)擊按鈕,可以看到DLLStatic中的模態(tài)對(duì)話框彈出。


            本例中,可以注意到DLL中所定義的About對(duì)話框資源與EXE中所定義的About對(duì)話框資源ID完全相同,但是當(dāng)我們點(diǎn)擊Use.exe上面的按鈕時(shí),彈出的是DLL中的模態(tài)對(duì)話框。說(shuō)明,當(dāng)使用靜態(tài)鏈接到MFC的規(guī)則DLL時(shí),不存在管理模塊狀態(tài)的問(wèn)題。

             
            2、動(dòng)態(tài)鏈接到MFC的DLL

            在討論關(guān)于動(dòng)態(tài)鏈接到MFC的DLL的模塊狀態(tài)問(wèn)題之前,先來(lái)看一個(gè)例子。本例可以通過(guò)如下步驟來(lái)完成:



            1)在VC菜單中File->New新建一個(gè)命名為DLLShared的MFC AppWizard的工程,下一步選擇Regular DLL using shared MFC DLL。



            2)在工程中添加一個(gè)對(duì)話框資源,其ID為:IDD_ABOUTBOX。并在resource.h之中將IDD_ABOUTBOX 的數(shù)值改為100。



            3)在DLLShared.cpp中定義如下函數(shù):



            void ShowDlg()

            {

            CDialog dlg(IDD_ABOUTBOX);

            dlg.DoModal();

            }



            4)在DLLShared.def文件中的EXPORTS語(yǔ)句中添加一行:ShowDlg,以導(dǎo)出ShowDlg函數(shù)。



            5)編譯生成DLLShared.dll和DLLShared.lib。



            繼續(xù)使用上面的Use工程,將前面生成的DLLShared.dll和DLLShared.lib兩個(gè)文件復(fù)制到工程的Debug目錄內(nèi),并將



            extern "C" __declspec(dllexport) void ShowDlg();

            #pragma comment(lib,"debug/DLLStatic")



            這兩行改為:



            void ShowDlg();

            #pragma comment(lib,"debug/DLLShared")



            編譯并運(yùn)行Use.exe。點(diǎn)擊按鈕,這次你看到了什么?對(duì),沒(méi)錯(cuò),這次彈出的是Use.exe的關(guān)于對(duì)話框。將上述例子的DLL類(lèi)型換成MFC Extension DLL(using shared MFC DLL)也會(huì)出現(xiàn)相同的問(wèn)題。



            為什么會(huì)出現(xiàn)上面的問(wèn)題?這是因?yàn)樵谑褂昧薓FC共享庫(kù)的時(shí)候,默認(rèn)情況下,MFC使用主應(yīng)用程序的資源句柄來(lái)加載資源模板。雖然我們調(diào)用的是DLL中的函數(shù)來(lái)顯示DLL中的對(duì)話框,并且對(duì)應(yīng)的對(duì)話框模板是存儲(chǔ)在DLL中的,但MFC仍舊在主應(yīng)用程序也就是Use.exe中尋找相應(yīng)的對(duì)話框模板。由于在DLL中所定義的對(duì)話框資源ID與主應(yīng)用程序中所定義的關(guān)于對(duì)話框的資源ID相同,所以MFC就把主應(yīng)用程序中的關(guān)于對(duì)話框顯示了出來(lái)。如果二者不同,則MFC就認(rèn)為DLL中所定義的對(duì)話框資源不存在,dlg.DoModal會(huì)返回0,也就是什么都不會(huì)顯示。



            那么如何解決上述問(wèn)題呢?解決辦法就是在適當(dāng)?shù)臅r(shí)候進(jìn)行模塊狀態(tài)切換,以保證具有當(dāng)前狀態(tài)的模塊是我們所需要的模塊從而使用正確的資源。MFC提供了下列函數(shù)和宏來(lái)完成這些工作:



            AfxGetStaticModuleState:這是一個(gè)函數(shù),其函數(shù)原型為:



            AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState( );



            此函數(shù)在堆棧上構(gòu)造AFX_MODULE_STATE類(lèi)的實(shí)例pModuleState并對(duì)其賦值后將其返回。在AFX_MODULE_STATE類(lèi)的構(gòu)造函數(shù)中,該類(lèi)獲取指向當(dāng)前模塊狀態(tài)的指針并將其存儲(chǔ)在成員變量中,然后將pModuleState設(shè)置為新的有效模塊狀態(tài)。在它的析構(gòu)函數(shù)中,該類(lèi)將存儲(chǔ)在其成員變量中的指針還原為存貯的前一個(gè)模塊狀態(tài)。



            AFX_MANAGE_STATE:這是一個(gè)宏,其原型為:



            AFX_MANAGE_STATE( AFX_MODULE_STATE* pModuleState )



            該宏用于將pModuleState(指向包含模塊全局?jǐn)?shù)據(jù)也就是模塊狀態(tài)的AFX_MODULE_STATE結(jié)構(gòu)的指針)設(shè)置為當(dāng)前的即時(shí)作用空間中(the remainder of the immediate containing scope)的有效模塊狀態(tài)。在離開(kāi)包含該宏的作用空間時(shí),前一個(gè)有效的模塊狀態(tài)自動(dòng)還原。



            AfxGetResourceHandle:這個(gè)函數(shù)的原型為:



            HINSTANCE AfxGetResourceHandle( );



            該函數(shù)返回了一個(gè)保存了HINSTANCE類(lèi)型的、應(yīng)用程序默認(rèn)所加載資源的模塊的句柄。



            AfxSetResourceHandle:這個(gè)函數(shù)的原型為:



            void AfxSetResourceHandle( HINSTANCE hInstResource );



            該函數(shù)將hInstResource所代表的模塊設(shè)置為具有當(dāng)前狀態(tài)的模塊。



            通過(guò)使用上述四個(gè)函數(shù)或宏就可以正確的在動(dòng)態(tài)鏈接到MFC的DLL中切換模塊狀態(tài)。接下來(lái)我們將通過(guò)修改上面出現(xiàn)問(wèn)題的那個(gè)例子來(lái)介紹如何使用上述四個(gè)函數(shù)或宏。先來(lái)看看Regular DLL using shared MFC DLL類(lèi)型:



            在上述例子的第三步的ShowDlg函數(shù)的第一條語(yǔ)句前加上如下語(yǔ)句(要確保該語(yǔ)句在函數(shù)實(shí)現(xiàn)的第一行):



            AFX_MANAGE_STATE(AfxGetStaticModuleState());



            之后重新編譯生成DLLShared.dll和DLLShared.lib,并將這兩個(gè)文件重新拷貝到Use工程的Debug目錄內(nèi)。這次編譯生成Use.exe并運(yùn)行,點(diǎn)擊按鈕,可以看到彈出的時(shí)我們?cè)贒LL中所加入的那個(gè)對(duì)話框,而不再是Use.exe的關(guān)于對(duì)話框了。



            通過(guò)上面的講解,相信你已經(jīng)知道該語(yǔ)句的作用了。在函數(shù)ShowDlg的第一行加上這么一句后,每次調(diào)用DLL的應(yīng)用程序使用該函數(shù)的時(shí)候,MFC庫(kù)都會(huì)自動(dòng)切換當(dāng)前模塊狀態(tài),這樣就保證了資源讀取的正確性。



            AFX_MANAGE_STATE(AfxGetStaticModuleState());是自動(dòng)切換當(dāng)前模塊狀態(tài),也可以通過(guò)使用AfxGetResourceHandle和AfxSetResourceHandle來(lái)手動(dòng)切換當(dāng)前模塊狀態(tài)。具體使用方法如下:



            在上述例子的第三步的ShowDlg函數(shù)的第一條語(yǔ)句前加上如下語(yǔ)句(要確保該語(yǔ)句在函數(shù)實(shí)現(xiàn)的第一行):



            HINSTANCE save_hInstance = AfxGetResourceHandle();

            AfxSetResourceHandle(theApp.m_hInstance);



            在調(diào)用對(duì)話框成功之后,也就是dlg.DoModal();之后,添加:



            AfxSetResourceHandle(save_hInstance);



            這種方法在進(jìn)入ShowDlg函數(shù)之后,通過(guò)AfxGetResourceHandle來(lái)獲得并保存當(dāng)前狀態(tài)模塊的句柄。然后獲得DLL模塊的句柄theApp.m_hInstance(當(dāng)然,也可以使用GetModuleHandle函數(shù)來(lái)獲得DLL模塊的句柄),并使用AfxSetResourceHandle函數(shù)來(lái)將其設(shè)置為當(dāng)前狀態(tài)狀態(tài)。最后在調(diào)用對(duì)話框成功之后再用恢復(fù)AfxSetResourceHandle資源句柄,將當(dāng)前模塊狀態(tài)恢復(fù)。



            這樣做有些麻煩,但是有一點(diǎn)好處是可以在完成使用資源的任務(wù)之后就可以立即恢復(fù)資源句柄。而AFX_MANAGE_STATE(AfxGetStaticModuleState());的方法只能等函數(shù)的作用空間結(jié)束之后才恢復(fù)資源句柄。由于可執(zhí)行文件必須重畫(huà)工具條等原因,因此建議只要有可能就必須恢復(fù)資源句柄,否則可能會(huì)遇到許多問(wèn)題。比如說(shuō),如果用戶(hù)移動(dòng)DLL的對(duì)話框,而此時(shí)資源句柄仍然為DLL的資源,那么程序就會(huì)崩潰。最好的恢復(fù)句柄的時(shí)機(jī)在對(duì)話框響應(yīng)WM_INITDIALOG消息的時(shí)候,因?yàn)檫@時(shí)對(duì)話框的模板等已經(jīng)讀出了。


            對(duì)于MFC Extension DLL(using shared MFC DLL)類(lèi)型的MFC DLL,切換當(dāng)前模塊狀態(tài)的方法與Regular DLL using shared MFC DLL類(lèi)型的MFC DLL所使用的方法很相似,這里不再舉例實(shí)現(xiàn)。二者不同的地方如下:



            在MFC擴(kuò)展DLL中使用AFX_MANAGE_STATE(AfxGetStaticModuleState());時(shí),會(huì)產(chǎn)生如下錯(cuò)誤:



            mfcs42d.lib(dllmodul.obj) : error LNK2005: __pRawDllMain already defined in dllextend.obj

            mfcs42d.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in dllextend.obj

            mfcs42d.lib(dllmodul.obj) : error LNK2005: __pRawDllMain already defined in dllextend.obj



            因此在MFC擴(kuò)展DLL中需要將AFX_MANAGE_STATE(AfxGetStaticModuleState());換成AFX_MANAGE_STATE(AfxGetAppModuleState());才能正確切換當(dāng)前模塊狀態(tài)。



            在MFC擴(kuò)展DLL中使用AfxGetResourceHandle和AfxSetResourceHandle的方法與在Regular DLL using shared MFC DLL類(lèi)型的MFC DLL中所使用的方法相同。并且,DLL模塊的句柄可以通過(guò)MFC提供的DlgextentDLL這個(gè)結(jié)構(gòu)的hModule成員來(lái)獲得。即使用AfxSetResourceHandle(DlgextentDLL.hModule);語(yǔ)句。



            當(dāng)然,對(duì)于動(dòng)態(tài)鏈接到MFC的DLL,也可以在調(diào)用該DLL的MFC應(yīng)用程序中使用AfxGetResourceHandle和AfxSetResourceHandle兩個(gè)函數(shù)來(lái)切換當(dāng)前狀態(tài)模塊。該DLL模塊的句柄可以用GetModuleHandle函數(shù)來(lái)獲得。在此不再贅述。  

            posted @ 2008-07-22 18:14 深邃者 閱讀(377) | 評(píng)論 (0)編輯 收藏

            讓對(duì)話框?qū)PDATE_COMMAND_UI生效

             問(wèn)題:一般情況下我們用UPDATE_COMMAND_UI來(lái)修改菜單的狀態(tài)(enable/disable, check/uncheck, change text),但這個(gè)方法在一個(gè)基于對(duì)話框上的菜單卻沒(méi)有效果。
            void CTestDlg::OnUpdateFileExit(CCmdUI* pCmdUI)
            {
                 pCmdUI->Enable(FALSE);
                 pCmdUI->SetCheck(TRUE);
                 pCmdUI->SetRadio(TRUE);
                 pCmdUI->SetText("Close");
            //以上方法在MDI、SDI程序中都能起作用,在對(duì)話框中卻沒(méi)有效果,根本沒(méi)有調(diào)用這個(gè)函數(shù)。
            }
             
            原因分析:當(dāng)顯示一個(gè)下拉的菜單的時(shí)候,在顯示菜單前會(huì)發(fā)送WM_INITMENUPOPUP消息。而CFrameWnd::OnInitMenuPopup函數(shù)會(huì)刷新這個(gè)菜單項(xiàng),同時(shí)如果有UPDATE_COMMAND_UI響應(yīng)函數(shù),則調(diào)用它。通過(guò)它來(lái)更新反應(yīng)每個(gè)菜單的外觀效果(enabled/disabled, checked/unchecked).
            在一個(gè)基于對(duì)話框的程序中,因?yàn)闆](méi)有OnInitMenuPopup函數(shù),所以不會(huì)調(diào)用UPDATE_COMMAND_UI響應(yīng)函數(shù),而是使用了CWnd類(lèi)的默認(rèn)處理, 這種處理沒(méi)有調(diào)用UPDATE_COMMAND_UI響應(yīng)函數(shù)。

            解決方法如下:
            第一步:
            在對(duì)話框類(lèi)的.cpp文件,添加一個(gè)ON_WM_INITMENUPOPUP入口到消息映射里面
            BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
            //}}AFX_MSG_MAP
            ON_WM_INITMENUPOPUP()
            END_MESSAGE_MAP()
            第二步:
            在對(duì)話框類(lèi)的.h文件添加消息函數(shù)聲明。
            // Generated message map functions
            //{{AFX_MSG(CDisableDlgMenuDlg)
            afx_msg void OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu);
            //}}AFX_MSG
            DECLARE_MESSAGE_MAP()
            第三步:
            在對(duì)話框類(lèi)的.cpp文件添加如下函數(shù)代碼(大部分代碼取自WinFrm.cpp文件的函數(shù)CFrameWnd::OnInitMenuPopup):
            void C******Dlg::OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu)
            {
                 ASSERT(pPopupMenu != NULL);
                // Check the enabled state of various menu items.

                CCmdUI state;
                state.m_pMenu = pPopupMenu;
                ASSERT(state.m_pOther == NULL);
                ASSERT(state.m_pParentMenu == NULL);

                // Determine if menu is popup in top-level menu and set m_pOther to
                // it if so (m_pParentMenu == NULL indicates that it is secondary popup).
                HMENU hParentMenu;
                if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu)
                     state.m_pParentMenu = pPopupMenu;??? // Parent == child for tracking popup.
               else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
               {
                   CWnd* pParent = this;
                   // Child windows don't have menus--need to go to the top!
                   if (pParent != NULL &&
            (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
                  {
                       int nIndexMax = ::GetMenuItemCount(hParentMenu);
                      for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
                     {
                         if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu)
                         {
                            // When popup is found, m_pParentMenu is containing menu.
                            state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
                            break;
                         }
                     }
                }
            }

              state.m_nIndexMax = pPopupMenu->GetMenuItemCount();
              for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
              state.m_nIndex++)
              {
                  state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);
                  if (state.m_nID == 0)
                      continue; // Menu separator or invalid cmd - ignore it.

                  ASSERT(state.m_pOther == NULL);
                  ASSERT(state.m_pMenu != NULL);
                  if (state.m_nID == (UINT)-1)
                  {
                      // Possibly a popup menu, route to first item of that popup.
                      state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex);
                      if (state.m_pSubMenu == NULL ||
             (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
            state.m_nID == (UINT)-1)
                   {
                          continue;    // First item of popup can't be routed to.
                   }
                   state.DoUpdate(this, TRUE);?? // Popups are never auto disabled.
                  }
                  else
                 {
                      // Normal menu item.
                      // Auto enable/disable if frame window has m_bAutoMenuEnable
                      // set and command is _not_ a system command.
                     state.m_pSubMenu = NULL;
                     state.DoUpdate(this, FALSE);
                  }

                  // Adjust for menu deletions and additions.
                  UINT nCount = pPopupMenu->GetMenuItemCount();
                  if (nCount < state.m_nIndexMax)
                    {
                               state.m_nIndex -= (state.m_nIndexMax - nCount);
                               while (state.m_nIndex < nCount &&
                              pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
                       {
                        state.m_nIndex++;
                        }
                   }
                    state.m_nIndexMax = nCount;
               }
            }

            posted @ 2008-07-17 11:42 深邃者 閱讀(209) | 評(píng)論 (0)編輯 收藏

            字符類(lèi)型數(shù)據(jù)轉(zhuǎn)換

                 摘要: 1/**//**//**///////////////////////////////////////////////////////////////////////////  2// Module: stringutility.h  3// Conversion among wchar_t, ch...  閱讀全文

            posted @ 2008-07-15 08:49 深邃者 閱讀(164) | 評(píng)論 (0)編輯 收藏

            僅列出標(biāo)題
            共5頁(yè): 1 2 3 4 5 
            少妇精品久久久一区二区三区| 欧美激情精品久久久久久| 久久国产视频99电影| 狠狠久久综合| 亚洲AV无码久久精品色欲| 国产日产久久高清欧美一区| 久久亚洲国产成人影院网站| 久久精品国产免费观看三人同眠| 国产成人精品久久| 香港aa三级久久三级老师2021国产三级精品三级在| 久久亚洲中文字幕精品一区| 久久青草国产精品一区| 久久综合88熟人妻| 一本久久免费视频| 久久99九九国产免费看小说| 精品无码久久久久国产| 久久精品中文无码资源站| 99久久夜色精品国产网站| 久久精品这里热有精品| 欧美一区二区三区久久综| 香蕉99久久国产综合精品宅男自 | 精品国产VA久久久久久久冰| 国产综合精品久久亚洲| 久久亚洲AV成人出白浆无码国产| 久久这里的只有是精品23| 久久青青草原精品国产软件| 青青国产成人久久91网| 国产精品免费福利久久| 久久久久亚洲AV无码网站| 久久精品国产亚洲AV不卡| 中文国产成人精品久久不卡| 久久精品国产亚洲av麻豆蜜芽| 中文成人久久久久影院免费观看| 性做久久久久久久久久久| 久久国产精品偷99| 一本大道久久东京热无码AV| 久久久久人妻精品一区三寸蜜桃| 精品久久久久中文字幕一区| 久久国产高清一区二区三区| 亚洲国产日韩综合久久精品| 蜜臀av性久久久久蜜臀aⅴ|