Rảnh rỗi mình ngồi viết tut, mong các bạn ủng hộ nhé.
Chúng ta sẽ bắt đầu "động chạm" tới WINAPI, mà dân lập trình cứ hay gọi nó là lập trình WINDOW, khá là phức tạp, khó nhớ và nhanh nản.
Hồi mới học C mình cũng nghĩ là khi học xong sẽ làm được các ứng dụng này nọ, nhưng chỉ học console thì chắc chả làm được cái gì ngoài code mấy bài giải phương trình bậc 2, vì trình mình kém không đủ kiên nhẫn học tiếp cũng như chả có ai định hướng cho cả. Sau đó mình chia tay C/C++ một thời gian rồi chuyển lung tung qua C#, android hay java. Thật sự bây giờ nhìn lại mình thấy thế này: C# là ngôn ngữ dễ học, cứ kéo thả ầm ầm, viết 1 cái ứng dụng nhanh lắm vì nó hỗ trợ nhiều, nhưng mà vì dễ học nên số lượng coder về cái này cũng khá là nhiều, nhan nhản :D
java thì đồ chùa, nghĩa là không phải lo vấn đề bản quyền lắm khi bạn viết 1 ứng dụng đem đi bán, nó là mã mở mà. Nó học cũng khá hay, hiện tại làm game mạnh mẽ nhất có lẽ là thằng java này. Mình ít xài java vì mặc dù thích chơi game, nhưng ghét code game.
Mình chán mấy thứ đó, mà có lẽ do tính mình nhanh nản, học gì cũng học được 1 tý chứ chả chuyên sâu gì, vậy nên nếu các bạn đang có tâm lý như mình thì nên thay đổi đi. Phải kiên định các bạn ạ :)
Mình viết tút về lập trình WINAPI, có mục đích là muốn quay lại với em C/C++ khó xơi này. Thứ hai muốn học từ đầu và không muốn lan man nhiều ngôn ngữ nữa, mình cũng thích mình giỏi về cái này. Bạn nào đọc đến đây thấy nản thì thôi nhé.
hihi, lan man nhiều quá. Ta bắt đầu với chương trình helloWorld luôn nhé.
Đầu tiên mình cần các bạn cài Dev-C cho mình, vì mình cũng đang dung cái này để viết tut. Tất nhiên các bạn có thể dung Cfree(thực ra là không free), hay visual C,. nhưng thôi cứ theo mình nhé :D
Các bạn cài đặt Dev-C cho mình nhé. Nếu bạn nào cài Win8 thì cài đúng bản giành cho Win8 vì bản cài đơn thuần bị lỗi không chạy được thư viện g++ đâu nhé. Link thì
nhấn đây để tải nhé :v
Oki rồi, bây giờ mình có 1 đoạn code như sau rồi anh em cùng phân tích xem nó viết cái gì nhé:
#include <windows.h>
const char g_szClassName[] = "myWindowClass";
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Nhìn đoạn code màu xanh trên hơi nản đúng không anh em? Mình cũng vậy, đúng là nó lạ hoắc và lại dài loằng ngoằng. Nói that mình đã bỏ cuộc khi nhìn thấy nó trong 1 thời gian. Bây giờ anh em nào còn kiên trì thì đọc nốt nhé. Mình sẽ phân tích từng đoạn 1. Anh em copy đoạn màu xanh rồi cho vào dev-C, nhấn F9 cho nó chạy được file exe ở cùng mục code luôn.
Còn bây giờ thì đọc phân tích này:
#include <windows.h>
Đoạn khai báo thư viện windows.h để anh em có thể dung những tiện ích mà thư viện này mang lại. Tương tự như khai báo conio thì dung getch, stdio thì dung printf đó anh em!
const char g_szClassName[] = "myWindowClass";
Đoạn này là khai báo 1 kiểu hàm char - kiểu mảng ký tự và chưa biết có bao nhiêu ký tự nên người ta đặt tên mảng là szClassName có [], sau đó gán xâu
"myWindowClass" cho mảng này luôn.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
Toàn bộ thủ tục này hơi loằng nhoằng nhưng anh em bình tĩnh nào. Thủ tục có tên là
CALLBACK do windows định nghĩa sẵn cấu trúc rồi, phía trong có lệnh switch để xử lý từng sự kiện. Thủ tục này chạy được thì cần những thông số sau:
HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
nhưng anh em chưa vội quan tâm vì bài mở đầu nên mình cũng chả muốn dọa ai cả. cứ biết nó cần là được. Các bài sau code nhiều một tý là anh em sẽ hiểu ra thôi.
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
cấu trúc switch có lẽ anh em biết cả rồi. Nó là lựa chọn với biến msg - biến thông điệp khi người dung làm gì đó với cái cửa sổ mà anh em vừa tạo bang code. Ở đây case
WM_CLOSE nghĩa là khi anh em chọn vào nút đóng cửa sổ, nó sẽ làm
DestroyWindow(hwnd) nghĩa là tắt cái windows luôn và đóng chương trình. với WM_DESTROY thì sẽ PostQuitMessage(0); - thông báo thoát chương trình. Mặc định ngoài hai sự kiện trên mà không xảy ra thì nó sẽ liên tục vẽ lại cửa sổ DefWindowProc(hwnd, msg, wParam, lParam)
Bài tiếp mình sẽ giới thiệu 1 số thông điệp khác mà anh em có thể dùng.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Anh em lại ngứa rồi đúng không, nhưng bình tĩnh ta sẽ gỡ từng cái một.
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
Đoạn này là Window đang đăng ký với hệ điều hành các thông số để khởi tạo cửa sổ. Như là kích thước cửa sổ, kiểu cửa sổ, icon ứng dụng, con trỏ, kiểu menu, kiểu hình nền....
Thiếu bất cứ cái nào cũng không chạy được.
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
Thằng if trên nó tạo ra 1 cái hộp thông báo có dòng tiêu đề là error(lỗi), thông báo là đăng ký window bị lỗi!
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
Khi anh em đăng ký không bị lỗi thì bắt đầu "vẽ" cái cửa sổ ra, vẽ bang code bao gồm kích thước, kiểu cửa sổ,... Và nếu như vẽ không được thì nhã lỗi cho người lập trình xem.
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
Hiển thị cửa sổ lên và cập nhật liên tục cửa sổ.
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return
Vòng lặp tin nhắn:
Hàm
GetMessage là để lấy thông tin từ người dung như bàn phím, click chuột, rê chuột....và nếu như nó trả về gt>0 thì bắt đầu thực hiện 2 câu lệnh:
dịch tin nhắn để hiểu nó là tin nhắn gì. Và thứ 2 là
gửi tin nhắn ra cửa sổ thông điệp đã được gửi đến.
Bài 1 kết thúc tại đây. Nếu anh em thắc mắc bài 1 có thể xem bài 2 tiếp theo của mình. Anh em nào muốn hỏi cũng có thể inbux tại:
quynhlxbkhn@gmail.com
(28/1/2014)