理論:
Windows 程序中,在寫(xiě)圖形用戶界面時(shí)需要調(diào)用大量的標(biāo)準(zhǔn) Windows Gui 函數(shù)。其實(shí)這對(duì)用戶和程序員來(lái)說(shuō)都有好處,對(duì)于用戶,面對(duì)的是同一套標(biāo)準(zhǔn)的窗口,對(duì)這些窗口的操作都是一樣的,所以使用不同的應(yīng)用程序時(shí)無(wú)須重新學(xué)習(xí)操作。對(duì)程序員來(lái)說(shuō),這些 Gui 源代碼都是經(jīng)過(guò)了微軟的嚴(yán)格測(cè)試,隨時(shí)拿來(lái)就可以用的。當(dāng)然至于具體地寫(xiě)程序?qū)τ诔绦騿T來(lái)說(shuō)還是有難度的。為了創(chuàng)建基于窗口的應(yīng)用程序,必須嚴(yán)格遵守規(guī)范。作到這一點(diǎn)并不難,只要用模塊化或面向?qū)ο蟮木幊谭椒纯伞?
下面我就列出在桌面顯示一個(gè)窗口的幾個(gè)步驟:
得到您應(yīng)用程序的句柄(必需); 得到命令行參數(shù)(如果您想從命令行得到參數(shù),可選); 注冊(cè)窗口類(必需,除非您使用 Windows 預(yù)定義的窗口類,如 MessageBox 或 dialog box; 產(chǎn)生窗口(必需); 在桌面顯示窗口(必需,除非您不想立即顯示它); 刷新窗口客戶區(qū); 進(jìn)入無(wú)限的獲取窗口消息的循環(huán); 如果有消息到達(dá),由負(fù)責(zé)該窗口的窗口回調(diào)函數(shù)處理; 如果用戶關(guān)閉窗口,進(jìn)行退出處理。 相對(duì)于單用戶的 DOS 下的編程來(lái)說(shuō),Windows 下的程序框架結(jié)構(gòu)是相當(dāng)復(fù)雜的。但是 Windows 和 DOS 在系統(tǒng)架構(gòu)上是截然不同的。Windows 是一個(gè)多任務(wù)的操作系統(tǒng),故系統(tǒng)中同時(shí)有多個(gè)應(yīng)用程序彼此協(xié)同運(yùn)行。這就要求 Windows 程序員必須嚴(yán)格遵守編程規(guī)范,并養(yǎng)成良好的編程風(fēng)格。 內(nèi)容: 下面是我們簡(jiǎn)單的窗口程序的源代碼。在進(jìn)入復(fù)雜的細(xì)節(jié)前,我將提綱挈領(lǐng)地指出幾點(diǎn)要點(diǎn): 您應(yīng)當(dāng)把程序中要用到的所有常量和結(jié)構(gòu)體的聲明放到一個(gè)頭文件中,并且在源程序的開(kāi)始處包含這個(gè)頭文件。這么做將會(huì)節(jié)省您大量的時(shí)間,也免得一次又一次的敲鍵盤。目前,最完善的頭文件是 hutch 寫(xiě)的,您可以到 hutch 或我的網(wǎng)站下載。您也可以定義您自己的常量和結(jié)構(gòu)體,但最好把它們放到獨(dú)立的頭文件中 用 includelib 指令,包含您的程序要引用的庫(kù)文件,譬如:若您的程序要調(diào)用 "MessageBox",您就應(yīng)當(dāng)在源文件中加入如下一行: includelib user32.lib 這條語(yǔ)句告訴 MASM 您的程序?qū)⒁玫揭恍┮霂?kù)。如果您不止引用一個(gè)庫(kù),只要簡(jiǎn)單地加入 includelib 語(yǔ)句,不要擔(dān)心鏈接器如何處理這么多的庫(kù),只要在鏈接時(shí)用鏈接開(kāi)關(guān) /LIBPATH 指明庫(kù)所在的路徑即可。 在其它地方運(yùn)用頭文件中定義函數(shù)原型,常數(shù)和結(jié)構(gòu)體時(shí),要嚴(yán)格保持和頭文件中的定義一致,包括大小寫(xiě)。在查詢函數(shù)定義時(shí),這將節(jié)約您大量的時(shí)間; 在編譯,鏈接時(shí)用makefile文件,免去重復(fù)敲鍵。 .386 .model flat,stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\user32.inc includelib \masm32\lib\user32.lib ; calls to functions in user32.lib and kernel32.lib include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib WinMain proto :DWORD,:DWORD,:DWORD,:DWORD .DATA ; initialized data ClassName db "SimpleWinClass",0 ; the name of our window class AppName db "Our First Window",0 ; the name of our window .DATA? ; Uninitialized data hInstance HINSTANCE ? ; Instance handle of our program CommandLine LPSTR ? .CODE ; Here begins our code start: invoke GetModuleHandle, NULL ; get the instance handle of our program. ; Under Win32, hmodule==hinstance mov hInstance,eax mov hInstance,eax invoke GetCommandLine ; get the command line. You don't have to call this function IF ; your program doesn't process the command line. mov CommandLine,eax invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT ; call the main function invoke ExitProcess, eax ; quit our program. The exit code is returned in eax from WinMain. WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD LOCAL wc:WNDCLASSEX ; create local variables on stack LOCAL msg:MSG LOCAL hwnd:HWND mov wc.cbSize,SIZEOF WNDCLASSEX ; fill values in members of wc mov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc, OFFSET WndProc mov wc.cbClsExtra,NULL mov wc.cbWndExtra,NULL push hInstance pop wc.hInstance mov wc.hbrBackground,COLOR_WINDOW 1 mov wc.lpszMenuName,NULL mov wc.lpszClassName,OFFSET ClassName invoke LoadIcon,NULL,IDI_APPLICATION mov wc.hIcon,eax mov wc.hIconSm,eax invoke LoadCursor,NULL,IDC_ARROW mov wc.hCursor,eax invoke RegisterClassEx, addr wc ; register our window class invoke CreateWindowEx,NULL,\ ADDR ClassName,\ ADDR AppName,\ WS_OVERLAPPEDWINDOW,\ CW_USEDEFAULT,\ CW_USEDEFAULT,\ CW_USEDEFAULT,\ CW_USEDEFAULT,\ NULL,\ NULL,\ hInst,\ NULL mov hwnd,eax invoke ShowWindow, hwnd,CmdShow ; display our window on desktop invoke UpdateWindow, hwnd ; refresh the client area .WHILE TRUE ; Enter message loop invoke GetMessage, ADDR msg,NULL,0,0 .BREAK .IF (!eax) invoke TranslateMessage, ADDR msg invoke DispatchMessage, ADDR msg .ENDW mov eax,msg.wParam ; return exit code in eax ret WinMain endp WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .IF uMsg==WM_DESTROY ; if the user closes our window invoke PostQuitMessage,NULL ; quit our application .ELSE invoke DefWindowProc,hWnd,uMsg,wParam,lParam ; Default message processing ret .ENDIF xor eax,eax ret WndProc endp end start 分析: 看到一個(gè)簡(jiǎn)單的 Windows 程序有這么多行,您是不是有點(diǎn)想撤? 但是您必須要知道的是上面的大多數(shù)代碼都是模板而已,模板的意思即是指這些代碼對(duì)差不多所有標(biāo)準(zhǔn) Windows 程序來(lái)說(shuō)都是相同的。在寫(xiě) Windows 程序時(shí)您可以把這些代碼拷來(lái)拷去,當(dāng)然把這些重復(fù)的代碼寫(xiě)到一個(gè)庫(kù)中也挺好。其實(shí)真正要寫(xiě)的代碼集中在 WinMain 中。這和一些 C 編譯器一樣,無(wú)須要關(guān)心其它雜務(wù),集中精力于 WinMain 函數(shù)。唯一不同的是 C 編譯器要求您的源代碼有必須有一個(gè)函數(shù)叫 WinMain。否則 C 無(wú)法知道將哪個(gè)函數(shù)和有關(guān)的前后代碼鏈接。相對(duì)C,匯編語(yǔ)言提供了較大的靈活性,它不強(qiáng)行要求一個(gè)叫 WinMain 的函數(shù)。 下面我們開(kāi)始分析,您可得做好思想準(zhǔn)備,這可不是一件太輕松的活。 .386 .model flat,stdcall option casemap:none WinMain proto :DWORD,:DWORD,:DWORD,:DWORD include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib 您可以把前三行看成是"必須"的. .386告訴MASN我們要用80386指令集。 . model flat,stdcall告訴MASM 我們用的內(nèi)存尋址模式,此處也可以加入stdcall告訴MASM我們所用的參數(shù)傳遞約定。 接下來(lái)是函數(shù) WinMain 的原型申明,因?yàn)槲覀兩院笠玫皆摵瘮?shù),故必須先聲明。我們必須包含 window.inc 文件,因?yàn)槠渲邪罅恳玫降某A亢徒Y(jié)構(gòu)的定義,該文件是一個(gè)文本文件,您可以用任何文本編輯器打開(kāi)它, window.inc還沒(méi)有包含所有的常量和結(jié)構(gòu)定義,不過(guò) hutch 和我一直在不斷加入新的內(nèi)容。 |
免責(zé)聲明:本站部分文章和圖片均來(lái)自用戶投稿和網(wǎng)絡(luò)收集,旨在傳播知識(shí),文章和圖片版權(quán)歸原作者及原出處所有,僅供學(xué)習(xí)與參考,請(qǐng)勿用于商業(yè)用途,如果損害了您的權(quán)利,請(qǐng)聯(lián)系我們及時(shí)修正或刪除。謝謝!
始終以前瞻性的眼光聚焦站長(zhǎng)、創(chuàng)業(yè)、互聯(lián)網(wǎng)等領(lǐng)域,為您提供最新最全的互聯(lián)網(wǎng)資訊,幫助站長(zhǎng)轉(zhuǎn)型升級(jí),為互聯(lián)網(wǎng)創(chuàng)業(yè)者提供更加優(yōu)質(zhì)的創(chuàng)業(yè)信息和品牌營(yíng)銷服務(wù),與站長(zhǎng)一起進(jìn)步!讓互聯(lián)網(wǎng)創(chuàng)業(yè)者不再孤獨(dú)!
掃一掃,關(guān)注站長(zhǎng)網(wǎng)微信