日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

Windows API入门系列之五 -一个正儿八经的SDK程序

發(fā)布時(shí)間:2025/3/12 windows 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows API入门系列之五 -一个正儿八经的SDK程序 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上一篇,講了一個(gè)簡(jiǎn)單的SDK程序的多種版本的編寫,彈出了一個(gè)窗口,顯示了我們計(jì)算1到10的結(jié)果,計(jì)算的程序不是重點(diǎn),重點(diǎn)在于,一:讓大家認(rèn)識(shí)到Unicode版本的程序和ASCII版本的程序在編程方面的區(qū)別,以及怎么樣編寫出通用代碼的程序。二:怎么樣運(yùn)用API或者c++庫(kù)函數(shù)格式化非字符數(shù)據(jù)到一個(gè)字符串中顯示出來。

不過,那個(gè)相當(dāng)簡(jiǎn)單的程序,還算不上是一個(gè)正兒八經(jīng)的SDK程序,也就是說還不是一個(gè)純爺們兒,因?yàn)槲覀儾⒂H自完成一個(gè)SDK程序的經(jīng)典步驟。而是調(diào)用了一個(gè)MessageBox?API函數(shù),這個(gè)函數(shù)雖然使用簡(jiǎn)單,但是在它的內(nèi)部,那可是相當(dāng)復(fù)雜啊~~~。怎么個(gè)復(fù)雜法,具體的我不知道,但是我知道的是一個(gè)SDK程序的經(jīng)典步驟它是都用到了的,什么是編寫SDK程序的經(jīng)典步驟呢?新手朋友們聽好了哦,現(xiàn)在我就告訴你。

第一步:注冊(cè)窗口類

第二步:創(chuàng)建窗口

第三步:消息循環(huán)

第四步:編寫窗口消息處理函數(shù)

上面我所說的,聽起來都比較專業(yè),下面我就解釋一下,什么是注冊(cè)窗口類呢?注冊(cè)窗口類就是使用一個(gè)?窗口類結(jié)構(gòu)體(WNDCLASSEX)?來描述一類窗口,這類窗口具有相同的屬性,也就是你在結(jié)構(gòu)體WNDCLASSEX中指定的那些值。只要是用這個(gè)窗口類創(chuàng)建的窗口都具有這些特性。至于WNDCLASS能描述哪些特性,下面會(huì)具體講,這里你只要了解是用一個(gè)名叫WNDCLASSEX的結(jié)構(gòu)體來描述一個(gè)窗口的類別。

創(chuàng)建窗口應(yīng)該比較好理解吧,就是創(chuàng)建一個(gè)具體的窗口,好像是一句廢話嘛。也就是說這個(gè)窗口是根據(jù)一個(gè)窗口類而創(chuàng)建的,不是憑空而造的。意思是你要?jiǎng)?chuàng)建一個(gè)窗口,那么必須要有一個(gè)已經(jīng)注冊(cè)的窗口類。

對(duì)于前兩步,我打一個(gè)比方,就好比你要造一輛車,那們第一步首先是干什么??當(dāng)然是設(shè)計(jì)圖紙啦,圖紙上就有說明這種車有哪些特性。然后第二步才是根據(jù)這個(gè)圖紙來創(chuàng)建一個(gè)具體的看得見的車。所以我上面說的注冊(cè)窗口類就好比設(shè)計(jì)窗口的圖紙,然后就是根據(jù)這個(gè)窗口的圖紙來創(chuàng)建一個(gè)具體的窗口。都說成這樣了,應(yīng)該明了了吧~~

至于消息循環(huán),就是創(chuàng)建的窗口隨時(shí)都有可能發(fā)生很多事情,那么發(fā)生的這些事情怎么通知你呢?比如窗口最小化了,窗口大小改變了,怎么通知你呢???其實(shí)就就是通過消息循環(huán)不斷的取得窗口所發(fā)生的事情,然后以消息的形式發(fā)送給我們后面要介紹的窗口消息處理函數(shù)。

消息處理函數(shù)呢就是我們程序員負(fù)責(zé)編寫代碼對(duì)具體的消息進(jìn)行具體的處理,當(dāng)然你也可以不處理,交給系統(tǒng)的默認(rèn)處理函數(shù)來處理。

對(duì)于這兩步,我也打一個(gè)比方。消息循環(huán)就好比汽車的一個(gè)總傳感器,它源源不斷的將汽車內(nèi)部所發(fā)生的事情以消息的形式通過儀表板傳達(dá)給開車的人,開車的人根據(jù)具體的事情而采取具體的操作,當(dāng)然你也可以不操作,無動(dòng)于衷,對(duì)于windows消息來說,不操作倒沒有什么,而對(duì)于開車的人來說,不操作的后果就不好說了。?在這里,這個(gè)總傳感器就相當(dāng)于SDK程序的消息循環(huán),不斷的發(fā)送消息,而開車的人就相當(dāng)于窗口消息處理函數(shù),負(fù)責(zé)處理各種消息。明白了吧,還不明白的話就看看下面的具體的程序吧,也需還有最后一絲希望可以讓你恍然大悟。

講了正兒八經(jīng)的SDK程序的經(jīng)典步驟后,我們進(jìn)入正式的代碼階段,通過代碼結(jié)合上面所講理論進(jìn)一步鞏固知識(shí)。我講逐步講解并逐步編寫一個(gè)自己注冊(cè)窗口類,創(chuàng)建窗口,帶消息循環(huán),并自己編寫消息處理過程的程序。

首先給出程序框架

/*?BY?beyondcode?*/

#include?<windows.h>

#include?<tchar.h>

LRESULT?CALLBACK?WinMessageProc(?HWND?hwnd,?UINT?msg,?WPARAM?wParam,?LPARAM?lParam?);

int?WINAPI?_tWinMain(?HINSTANCE?hInstance,?HINSTANCE?hPrevInstance,?LPTSTR?lpCmdLine,?int?nShowCmd?)

{

return?0;

}

第一個(gè)函數(shù)聲明,返回類型為L(zhǎng)RESULT,本質(zhì)經(jīng)查看是long,然后函數(shù)調(diào)用約定CALLBACK和WINAPI是一樣的,都是__stdcall,說明函數(shù)調(diào)用相關(guān)的約定,不必深究。至于為什么用CALLBACK是為了意思顯而易見,表示是回調(diào)函數(shù),什么是回調(diào)函數(shù)?也就是系統(tǒng)負(fù)責(zé)調(diào)用的,不必你親自調(diào)用的函數(shù),所以你在你的程序里是看不到調(diào)用WinMessageProc這個(gè)函數(shù)的代碼的,你只負(fù)責(zé)編寫它的代碼,至于調(diào)用,系統(tǒng)會(huì)在有消息的時(shí)候自動(dòng)調(diào)用它。WinMessageProc的參數(shù)類型和個(gè)數(shù)是規(guī)定好了的,不然系統(tǒng)怎么知道怎么掉用,所以不能更改。

再解釋一下這四個(gè)參數(shù)吧,第一個(gè)參數(shù)是一個(gè)窗口的句柄,也就是告訴你,是哪個(gè)窗口的消息,第二個(gè)參數(shù)是消息的類型,告訴你是什么消息,第三個(gè)和第四個(gè)參數(shù)是這個(gè)消息所帶的一些額外的但是必須的數(shù)據(jù)。你在窗口消息處理函數(shù)中只使用他們就可以了,他們的值都是系統(tǒng)傳遞進(jìn)來的。你只是根據(jù)他們來判斷是哪個(gè)窗口的什么消息,并且獲取該消息的額外參數(shù)信息。

有了程序框架,我們來第一步,注冊(cè)一個(gè)窗口類

???//注冊(cè)一個(gè)名叫MyWindowClass的窗口類

WNDCLASSEX?wc;

wc.cbSize?=?sizeof(?wc?);

wc.style?=?CS_VREDRAW?|?CS_HREDRAW;

wc.cbClsExtra?=?0;

wc.cbWndExtra?=?0;

wc.hbrBackground?=?(HBRUSH)GetStockObject(WHITE_BRUSH);

wc.hCursor?=?LoadCursor(?NULL,?IDC_ARROW?);

wc.hIcon?=?LoadIcon(?NULL,?IDI_APPLICATION?);

wc.hIconSm?=?LoadIcon(?NULL,?IDI_APPLICATION?);

wc.hInstance?=?hInstance;

wc.lpfnWndProc?=?WinMessageProc;

wc.lpszMenuName?=?NULL;

wc.lpszClassName?=?_T("MyWindowClass");

if(?!RegisterClassEx(?&wc?)?)

{

MessageBox(?NULL,?_T("注冊(cè)窗口類出錯(cuò)"),?_T("出錯(cuò)"),?MB_OK?);

return?0;

}

上面的WNDCLASS的各個(gè)成員值我就不一一介紹是什么含義,MSDN上面講的非常清楚,我只講一兩個(gè)比較重點(diǎn)的,第一個(gè)lpszClassName這個(gè)成員,我們給它指定的是_T("MyWindowClass")這個(gè)值,這是指定這個(gè)窗口類的名字是什么,因?yàn)橄旅娴膭?chuàng)建窗口會(huì)用到這個(gè)名字。

lpfnWndProc這個(gè)成員是WinMessageProc這個(gè)函數(shù),這是指定這個(gè)窗口類所創(chuàng)建的窗口的消息處理函數(shù)是哪一個(gè),我們這里指定的是WinMessageProc。其他的參數(shù)我就不啰嗦了,各位不懂的MSDN一下或者在群里來交流一下。

指定了這個(gè)窗口類有哪些特性后就完了?當(dāng)然沒有,沒有注冊(cè)怎么使用啊,所以還需要注冊(cè),注冊(cè)調(diào)用RegisterClassEx這個(gè)API函數(shù),將剛才的WNDCLASS變量的地址傳給它就可以進(jìn)行注冊(cè)了,如果注冊(cè)失敗,返回值為零,成功的話返回值為非零。

注冊(cè)了窗口類,我們來第二步,創(chuàng)建一個(gè)窗口。代碼如下:

//?根據(jù)上面注冊(cè)的一個(gè)名叫MyWindowClass?的窗口類創(chuàng)建窗口

HWND?newWind?=?CreateWindowEx(?0L,?_T("MyWindowClass"),?_T("beyondcode"),?WS_OVERLAPPEDWINDOW,?0,?0,?200,?200,?NULL,?NULL,?hInstance,?NULL?);

if(?NULL==newWind?)

{

MessageBox(?NULL,?_T("創(chuàng)建窗口出錯(cuò)"),?_T("出錯(cuò)"),?MB_OK?);

return?0;

}

ShowWindow(?newWind,?nShowCmd?);

UpdateWindow(?newWind?);

可見,創(chuàng)建窗口用CreateWindowEx這個(gè)API函數(shù),它的第一個(gè)參數(shù)是擴(kuò)展樣式,我們這里不設(shè)置擴(kuò)展樣式,所以傳遞0L,第二個(gè)參數(shù)就是窗口類的名字,我們這里指定我們上面已經(jīng)注冊(cè)了的那個(gè)名叫MyWindowClass的窗口類,第三個(gè)參數(shù)是窗口的標(biāo)題,隨便設(shè)置,第四個(gè)參數(shù)是窗口的樣式,我們這里設(shè)置的是WS_OVERLAPPEDWINDOW,一般主窗口都用這個(gè)樣式,就是有最大化,最小化框,有標(biāo)題欄,有系統(tǒng)菜單。。具體的可以參見MSDN,第五個(gè),六個(gè),七個(gè),八個(gè)參數(shù)分別指定窗口的初始坐標(biāo)和長(zhǎng)寬,第九個(gè)參數(shù)指定父窗口是哪個(gè),這里沒有父窗口,所以傳遞NULL,第十個(gè)參數(shù)指定菜單的句柄,我們這里不設(shè)置菜單,所以傳遞NULL,第十一個(gè)是應(yīng)用程序句柄,用WinMain傳遞進(jìn)來的那個(gè)hInstance參數(shù),第十二個(gè)參數(shù)表示額外數(shù)據(jù),不設(shè)置,所以為NULL。

這個(gè)API函數(shù)有點(diǎn)復(fù)雜,不過用熟悉了也就不覺得了。這樣我們就創(chuàng)建了一個(gè)窗口,返回值是一個(gè)窗口的句柄,如果是NULL的話,說明創(chuàng)建窗口失敗了,如果不是NULL的話,說明成功了。

光創(chuàng)建成功了還不行,如果你不顯示和更新它,你還是看不到它,所以需要調(diào)用2個(gè)API函數(shù),ShowWindow和UpdateWindow,參數(shù)就是剛才創(chuàng)建成功的那個(gè)窗口的句柄,至于ShowWindow的第二個(gè)參數(shù)是指顯示的類型,是最大化顯示呢還是最小化顯示呢,不過在程序中第一次調(diào)用ShowWindow必須使用WinMain所傳遞進(jìn)來的參數(shù)的第四個(gè)參數(shù)的值。這是MSDN上說的~

窗口創(chuàng)建成功了,下面一步是消息循環(huán)了,消息循環(huán)說起來復(fù)雜,其實(shí)代碼挺簡(jiǎn)單的,而且基本格式固定,如下:

//消息循環(huán)

MSG?msg;

while(?GetMessage(?&msg,?NULL,?0,?0?)?)

{

TranslateMessage(?&msg?);

DispatchMessage(?&msg?);

}

看到了嗎??一直在一個(gè)循環(huán)里面,一直調(diào)用GetMessage,只要GetMessage所取得的消息不是WM_QUIT的話,那么GetMessage的返回值就不是0,那么循環(huán)就一直進(jìn)行。在循環(huán)內(nèi)部,將GetMessage取得的消息傳遞給TranslateMessage和DispatchMessage兩個(gè)API函數(shù)進(jìn)行處理.其中DispatchMessage就是將消息發(fā)送給了對(duì)應(yīng)的窗口的窗口消息處理函數(shù)進(jìn)行處理。至于TranslateMessage呢,則進(jìn)行一些消息的轉(zhuǎn)換,可以先不深究。

最后就是編寫窗口消息處理函數(shù)的代碼了,你需要處理那些消息,那么你就編寫處理那些消息的代碼,對(duì)于你不處理的消息,則統(tǒng)統(tǒng)交給一個(gè)叫DefWindowProc的API函數(shù)進(jìn)行默認(rèn)的處理。

LRESULT?CALLBACK?WinMessageProc(?HWND?hwnd,?UINT?msg,?WPARAM?wParam,?LPARAM?lParam?)

{

switch?(?msg?)

{

case?WM_DESTROY:

{

PostQuitMessage(?0?);

break;

}

default:

return?DefWindowProc(?hwnd,?msg,?wParam,?lParam?);

}

return?0;

}

這里我們只處理了WM_DESTROY這個(gè)消息,這個(gè)消息是在窗口被銷毀的時(shí)候發(fā)送給窗口消息處理函數(shù)的,在窗口處理函數(shù)中,我們判斷這個(gè)消息是不是WM_DESTROY,如果是,就調(diào)用PostQuitMessage這個(gè)API函數(shù),如果是其他消息,我們就不管,將參數(shù)全部傳遞給DefWindowProc這個(gè)函數(shù)進(jìn)行處理。

而PostQuitMessage這個(gè)API函數(shù)的功能就是發(fā)送一個(gè)WM_QUIT的消息。而我們前面說到過,?在消息循環(huán)中GetMessage一旦取得WM_QUIT這個(gè)消息,就返回值為0,那么消息循環(huán)也就結(jié)束了,進(jìn)而整個(gè)程序也就結(jié)束了,如果在這里我們處理WM_DESTORY函數(shù),但是不調(diào)用PostQuitMessage,那么結(jié)果會(huì)怎樣呢,讀者朋友們思考一下~~

好了,到這里,這個(gè)什么功能也沒有的SDK程序也就完了,它只顯示一個(gè)帶有標(biāo)題欄的可最大化,最小化的窗口,除了能夠關(guān)閉它,你幾乎不能進(jìn)行其他任何操作,因?yàn)槲覀兂颂幚泶翱阡N毀這個(gè)消息,其他任何消息我們都沒處理。

這篇文章中的源代碼在VS2008,windows?7平臺(tái)下編寫并完成編譯運(yùn)行,我會(huì)將源代碼上傳到群空間或其他地方,以方便新手朋友們對(duì)比學(xué)習(xí)~?

?

總結(jié)

以上是生活随笔為你收集整理的Windows API入门系列之五 -一个正儿八经的SDK程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。