學過一段時間的c++,建立的都是win32 console application,我來介紹一下如何建立一個簡單的win32程序,相比win32 console application,會有大家常見的窗口,更像程序一些。
首先要寫類似於main函數的WinMain,
int WINAPI WinMain( HINSTANCE hinstance,
HINSTANCE hprevinstance,
LPSTR lpcmdline,
int ncmdshow)
WINAPI是幹什麼的呢?它是調用聲明,相當於_stdcal。c++默認的調用聲明是_cdecl。兩者區別爲:
_stdcal函數在結束後自己清棧,_cdecl由調用者(不是指人自己,指的是調用的程序)清棧。當函數參數個數可變的時候,只能_cdecl調用,在不知道個數的情況下,函數自己不知道怎麼清棧;不同的編譯器會按不同的方式堆棧,這樣會使得如果使用_cdecl聲明時,調用者不一定可以成功清棧。
(參考了http://blog.csdn.net/dengziliang001/article/details/17448789)
hinstance是Windows爲應用程序產生的實例句柄,可以看成這個就是程序的地址,跟蹤程序。
hprevinstance,現在已經不使用這個參數了。
lpcmdline,與main中的命令行差不多,基本寫程序時不用管。
ncmdshow,帶有如何打開主應用程序窗口的信息,比如最大化,最小化,一般用的多的是ShowWindow(),ncmd不怎麼用。
函數體怎麼寫呢?看看下面:
WNDCLASSEX winclass; // this will hold the class we create
HWND hwnd;// generic window handle
MSG msg;// generic message
HDC hdc; // graphics device context
// first fill in the window class stucture
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC |
CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
WNDCLASSEX是一個類,因爲你要創建一個窗口,然後在上面輸入輸出操作,WNDCLSSEX可以看成一個窗口類,而winclass可以看成實例(即變量),hwnd,msg,hdc在後面會講到,首先要做的是填winclass的各個屬性,後面的一大串全是設置屬性,比較重要的是 winclass.style,它指出了窗口的重要屬性,如窗口寬度變化後會重畫,高度變化後會重畫,剩下的參數查msdn就知道了。
然後你需要去註冊這個類,
if (!RegisterClassEx(&winclass))
return(0);
外面的if,當沒註冊成功就返回0,防止程序沒註冊成功,往下運行出現未知的錯誤。
然後就是創建一個窗口,
if (!(hwnd = CreateWindowEx(NULL, // extended style
WINDOW_CLASS_NAME, // class
"Demo", // title
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0,0, // initial x,y
500,400, // initial width, height
NULL,
// handle to parent
NULL,
// handle to menu
hinstance,// instance of this application
NULL)))
// extra creation parms
return(0);
CreateWindowEx()會返回一個指向窗口的的句柄,相當於它的地址。
上面的一系列都可以直接複製張貼,根據需要,改一改屬性即可,然後我一般會編一個循環,去處理消息。
while(TRUE)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} // end if
} // end while
return(msg.wParam);
}
其中 if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
理解成先判斷有沒有消息,有的話就傳遞給相應的程序處理,消息可以使單擊鼠標左鍵,關閉窗口等。
之後return,就寫好主函數。
除了主函數還需要寫一個消息處理函數,每個窗口都有一個窗口處理函數,而關聯兩者,就是在設置窗口屬性時的winclass.lpfnWndProc= WindowProc,WindowProc是處理函數的名字,當窗口有相應的消息的時候,就會調用處理函數處理.下面是一個窗口處理函數:
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
PAINTSTRUCT ps;
switch(msg){
case WM_CREATE:
{
} break;
case WM_PAINT:
{
BeginPaint(hwnd,&ps);
EndPaint(hwnd,&ps);
return(0);
} break;
case WM_DESTROY:
{
PostQuitMessage(0);
return(0);
} break;
default:break;
}
return (DefWindowProc(hwnd, msg, wparam, lparam));
}
首先看一下函數的參數,hwnd 是調用窗口的句柄,便於對窗口操作,msg有消息類型的信息,wparam,lparam包含具體消息的細節。
總之其實上面的都可以直接複製張貼,至於該怎麼操作只需要改一下處理函數,還有在while循環裏做些填充。