1.2句柄及 WinMain函数
生活随笔
收集整理的這篇文章主要介紹了
1.2句柄及 WinMain函数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
***********************************************
* ? 本文由小鳥飛飛整理發表 <samboy@sohu.com> ? *
* ? 首發網站:藍麗網 ? ?? ?? ?? ?? ?? ?? *
* ? 其他網站轉載請保留以上信息,謝謝! ? ?? ?*
************************************************
關 于句柄
在Windows編程中我們時刻接觸到一個稱為句柄(HANDLE)的東西。可以這樣去理解句柄,Windows程序中產生的任何資源 (要占用某一塊或大或小的內存),如圖標,光標,窗口,應用程序的實例(已加載到內存運行中的程序)。操作系統每產生一個這樣的資源時,都要將它們放入相 應的內存,并為這些內存指定一個唯一的標識號,這個標識號即該資源的句柄。
操作系統要管理和操作這些資源,都是通過句柄來找到對應的 資源的。按資源的類型,又可將句柄細分成圖標句柄(HICON),光標句柄(HCURSOR),窗口句柄(HWND),應用程序實例句柄 (HINSTANCE),等等各種類型的句柄。操作系統給每一個窗口指定的一個唯一的標識號即窗口句柄。
WinMain函數
WinMain是Windows程序的入口點函數,同dos程序的入口點函數main的作用相同,當WinMain函數結束或返回時,Windows應用 程序結束。WinMain函數的原型如下:
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, ? ?// pointer to command line
int nCmdShow ? ?? ?// show state of window
);
該函數接受四個參數,這些參數都 是系統調用WinMain函數時,傳遞給應用程序的。
第一個參數hInstance表示該程序的當前運行的實例句柄。同一應用程序在 同一計算機上可運行多份實例,每啟動一個這樣的實例,操作系統都要給該實例分配一個標識號,即實例句柄,隨后系統調用程序中的WinMain函數,并將該 實例句柄傳遞給參數hInstance。
第二個參數hPrevInstance表示當前實例的上一個正在運行的,由同一個應用程序所 產生的實例的句柄,即當前實例的"哥哥"的句柄。如果該值為NULL,則表示當前實例是該程序正在運行的第一份實例,是“長子”,是“老大”。如果該值不 為NULL,只能表示當前實例不是該程序正在運行的第一份實例,不是“長子”,不是“老大”,但到底是“老幾”,就無從得知了。這個參數到底有什么作用 呢?如果想讓我們的程序只能有一份實例運行,不能同時有多份實例運行,我們可以在WinMain函數的開始部分加上如下代碼實現。
if(hPrevInstance) return 0;
我們再來看看if(hPrevInstance) return 0;的作用,如果hPrevInstance為NULL(即0),說明當前運行的實例是程序的第一個實例,WinMain函數將不返回,程序正常向下運 行。只要hPrevInstance不為NULL,說明已經有同樣程序的實例在運行,WinMain函數將返回,當前實例啟動后立馬結束,這樣就保證了只 有程序的一個實例可以運行。
第三個參數lpCmdLine是一個字符串,里面包含有傳遞給應用程序的參數串,如:雙擊C盤下的 1.txt文件方式啟動notepad.exe程序,傳遞給notepad.exe程序的參數串即"c:\1.txt",不包含應用程序名本身。要在VC 開發環境中給應用程序傳遞參數,請選擇菜單Project->Settings...,在彈出的Project Settings對話框中選擇Debug標簽,在該標簽頁的Program arguments編輯框中輸入你想傳遞給應用程序的參數。我們在WinMain函數的入口點設置一運行斷點,以調試方式啟動程序運行至該斷點處,將鼠標 移動到參數lpCmdLine上,在彈出的黃色小浮框中便能觀察到該變量的值。在我們的程序調試中,經常要用到這種方法查看變量的值和狀態。
第四個參數nCmdShow指定的程序的窗口應該如何顯示,如最大化,最小化,隱藏等。
WinMain函數前的修飾符WINAPI 的解釋,我們使用goto definition功能,發現WINAPI其實就是__stdcall。
__stdcall與 __cdecl是兩種不同的函數調用習慣,定義了參數的傳遞順序、堆棧清除等。關于它們的詳細信息請參看msdn。由于除了那些可變參數的API函數外, 其余的API函數都是__stdcall習慣。由于VC++程序默認的編譯選項是__cdecl,所以在VC++中調用這些__stdcall習慣的 API函數,必須在聲明這些函數的原型時加上__stdcall修飾符,以便對該函數的調用使用__stdcall習慣。我們曾有這樣的經驗,在 Delphi(默認的編譯選項是__stdcall)中編寫的dll中的函數,在VC++中被調用時,總是造成程序崩潰,在函數的原型聲明中加上 __stdcall修飾符,便解決了這個問題。回調函數也必須是__stdcall調用習慣,在這里是用CALLBACK來標識的,否則,在NT4.0環 境,程序將崩潰,但win98和win2000卻沒有這種現象。
Winmain函數的程序代碼按功能劃分主要有兩部分:1.產生并顯 示程序的主窗口。窗口創建并顯示后,用戶便可以在窗口上進行各種操作了,用戶的操作及程序狀態的變化都以消息的形式放到了應用程序的消息隊列中。2.從消 息隊列循環取走消息,并將消息派發到窗口過程函數中去處理。當消息循環取到一條WM_QUIT消息時,將結束循環,WinMain函數返回,結束整個程序 的運行。
如果WinMain在消息循環之前返回,程序沒有正常運行,返回值為0。如果在消息循環之后返回,返回值為WM_QIUT消息的 wParam參數。
* ? 本文由小鳥飛飛整理發表 <samboy@sohu.com> ? *
* ? 首發網站:藍麗網 ? ?? ?? ?? ?? ?? ?? *
* ? 其他網站轉載請保留以上信息,謝謝! ? ?? ?*
************************************************
關 于句柄
在Windows編程中我們時刻接觸到一個稱為句柄(HANDLE)的東西。可以這樣去理解句柄,Windows程序中產生的任何資源 (要占用某一塊或大或小的內存),如圖標,光標,窗口,應用程序的實例(已加載到內存運行中的程序)。操作系統每產生一個這樣的資源時,都要將它們放入相 應的內存,并為這些內存指定一個唯一的標識號,這個標識號即該資源的句柄。
操作系統要管理和操作這些資源,都是通過句柄來找到對應的 資源的。按資源的類型,又可將句柄細分成圖標句柄(HICON),光標句柄(HCURSOR),窗口句柄(HWND),應用程序實例句柄 (HINSTANCE),等等各種類型的句柄。操作系統給每一個窗口指定的一個唯一的標識號即窗口句柄。
WinMain函數
WinMain是Windows程序的入口點函數,同dos程序的入口點函數main的作用相同,當WinMain函數結束或返回時,Windows應用 程序結束。WinMain函數的原型如下:
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, ? ?// pointer to command line
int nCmdShow ? ?? ?// show state of window
);
該函數接受四個參數,這些參數都 是系統調用WinMain函數時,傳遞給應用程序的。
第一個參數hInstance表示該程序的當前運行的實例句柄。同一應用程序在 同一計算機上可運行多份實例,每啟動一個這樣的實例,操作系統都要給該實例分配一個標識號,即實例句柄,隨后系統調用程序中的WinMain函數,并將該 實例句柄傳遞給參數hInstance。
第二個參數hPrevInstance表示當前實例的上一個正在運行的,由同一個應用程序所 產生的實例的句柄,即當前實例的"哥哥"的句柄。如果該值為NULL,則表示當前實例是該程序正在運行的第一份實例,是“長子”,是“老大”。如果該值不 為NULL,只能表示當前實例不是該程序正在運行的第一份實例,不是“長子”,不是“老大”,但到底是“老幾”,就無從得知了。這個參數到底有什么作用 呢?如果想讓我們的程序只能有一份實例運行,不能同時有多份實例運行,我們可以在WinMain函數的開始部分加上如下代碼實現。
if(hPrevInstance) return 0;
我們再來看看if(hPrevInstance) return 0;的作用,如果hPrevInstance為NULL(即0),說明當前運行的實例是程序的第一個實例,WinMain函數將不返回,程序正常向下運 行。只要hPrevInstance不為NULL,說明已經有同樣程序的實例在運行,WinMain函數將返回,當前實例啟動后立馬結束,這樣就保證了只 有程序的一個實例可以運行。
第三個參數lpCmdLine是一個字符串,里面包含有傳遞給應用程序的參數串,如:雙擊C盤下的 1.txt文件方式啟動notepad.exe程序,傳遞給notepad.exe程序的參數串即"c:\1.txt",不包含應用程序名本身。要在VC 開發環境中給應用程序傳遞參數,請選擇菜單Project->Settings...,在彈出的Project Settings對話框中選擇Debug標簽,在該標簽頁的Program arguments編輯框中輸入你想傳遞給應用程序的參數。我們在WinMain函數的入口點設置一運行斷點,以調試方式啟動程序運行至該斷點處,將鼠標 移動到參數lpCmdLine上,在彈出的黃色小浮框中便能觀察到該變量的值。在我們的程序調試中,經常要用到這種方法查看變量的值和狀態。
第四個參數nCmdShow指定的程序的窗口應該如何顯示,如最大化,最小化,隱藏等。
WinMain函數前的修飾符WINAPI 的解釋,我們使用goto definition功能,發現WINAPI其實就是__stdcall。
__stdcall與 __cdecl是兩種不同的函數調用習慣,定義了參數的傳遞順序、堆棧清除等。關于它們的詳細信息請參看msdn。由于除了那些可變參數的API函數外, 其余的API函數都是__stdcall習慣。由于VC++程序默認的編譯選項是__cdecl,所以在VC++中調用這些__stdcall習慣的 API函數,必須在聲明這些函數的原型時加上__stdcall修飾符,以便對該函數的調用使用__stdcall習慣。我們曾有這樣的經驗,在 Delphi(默認的編譯選項是__stdcall)中編寫的dll中的函數,在VC++中被調用時,總是造成程序崩潰,在函數的原型聲明中加上 __stdcall修飾符,便解決了這個問題。回調函數也必須是__stdcall調用習慣,在這里是用CALLBACK來標識的,否則,在NT4.0環 境,程序將崩潰,但win98和win2000卻沒有這種現象。
Winmain函數的程序代碼按功能劃分主要有兩部分:1.產生并顯 示程序的主窗口。窗口創建并顯示后,用戶便可以在窗口上進行各種操作了,用戶的操作及程序狀態的變化都以消息的形式放到了應用程序的消息隊列中。2.從消 息隊列循環取走消息,并將消息派發到窗口過程函數中去處理。當消息循環取到一條WM_QUIT消息時,將結束循環,WinMain函數返回,結束整個程序 的運行。
如果WinMain在消息循環之前返回,程序沒有正常運行,返回值為0。如果在消息循環之后返回,返回值為WM_QIUT消息的 wParam參數。
總結
以上是生活随笔為你收集整理的1.2句柄及 WinMain函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1.1 Windows 程序运行原理(消
- 下一篇: 1.4 消息循环和回调函数