Tải bản đầy đủ (.pdf) (143 trang)

giáo trình lập trình c trên windows

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (2.7 MB, 143 trang )


5



Bài 1
TỔNG QUAN VỀ
LẬP TRÌNH WINDOWS
Không cần nói nhiều hơn, tất cả chúng ta ñều khá quen thuộc với việc sử dụng các ứng dụng trên
hệ ñiều hành Microsoft Windows. Trong bài học ñầu tiên này, tôi xin giới thiệu các ñặc ñiểm
chính của hệ ñiều hành này, ñồng thời cũng trình bày cách xây dựng ứng dụng cụ thể dạng
Win32 Application trên công cụ Visual C++ 6.0.
1.1. LẬP TRÌNH TRÊN MICROSOFT WINDOWS
Trong tất cả các môn học trước, hầu như chúng ta chỉ cài ñặt các chương trình, minh họa các
thuật toán,… dưới dạng các ứng dụng xử lý tuần tự theo lô (batch-oriented) hay giao tác
(transaction-oriented) gắn liền với hệ ñiều hành MS-DOS. Tuy nhiên, các ứng dụng trên
Windows thì hoàn toàn khác. Vì thế, phần này sẽ tóm tắt giúp các bạn các ñặc ñiểm chính của hệ
ñiều hành Windows, và cũng chính là các ñặc ñiểm của các ứng dụng khi lập trình trên môi
trường này.
1.1.1. Thông ñiệp và xử lý thông ñiệp
Khi chúng ta viết một chương trình dạng MS-DOS bằng ngôn ngữ C, yêu cầu duy nhất là ta phải
viết một hàm main. Hệ ñiều hành gọi hàm main khi chương trình ñược thực thi, và thực hiện
theo các cấu trúc lệnh ñã ñược lập trình từ trên xuống dưới.
Tuy nhiên, với Windows thì khác hẳn. Hệ ñiều hành Windows cũng gọi một hàm chính là
WinMain khi bắt ñầu tiến trình ñể thực hiện việc tạo lập cửa sổ ứng dụng, ứng dụng này ñược hệ
ñiều hành quản lý thông qua ñịa chỉ của tiến trình và vùng nhớ ñối tượng cửa sổ.
Các thao tác của người dùng - hoặc do các ñối tượng khác trên Windows - tác ñộng lên ứng
dụng ñều ñược chuyển thành một dạng thông tin gọi là thông ñiệp (message) và ñược hệ ñiều
hành quản lý. Hệ ñiều hành lần lượt chuyển các thông ñiệp ñến các cửa sổ nhận thao tác vừa thực
hiện. Khi lập trình, các thông ñiệp này ñều ñược gởi vào hàm xử lý của cửa sổ - thường ñặt tên là
WndProc ñối với cửa sổ chính của ứng dụng, và ta chỉ việc viết code ñể xử lý cho ứng dụng


thông qua các giá trị thông ñiệp (tương ứng các thao tác) ñã ñược Windows ñịnh nghĩa sẵn.
1.1.2. Giao diện ñồ họa người dùng GUI
Vấn ñề xử lý thông ñiệp là ñặc ñiểm quan trọng nhất, tuy nhiên khi ñề cập ñến lập trình trên
Windows người ta lại thường chú ý tới ñặc trưng giao diện (visual interface) của các ứng dụng
hơn.
Trên môi trường Windows, các ứng dụng giao tiếp (trao ñổi thông tin) với người dùng thông
6

qua các ñối tượng trực quan như cửa sổ (window), thanh trình ñơn (menu), hộp hội thoại (dialog
box), các ñối tượng ñiều khiển (controls)…
Khi lập trình, chúng ta sử dụng các hàm API (Application Programming Interface), cơ chế
liên kết ñộng DLL (Dynamic Link Library) và hệ thống tài nguyên (resource-based
programming) của IDE (Intergrated Development Environment) ñể xây dựng giao diện các ứng
dụng theo các ñịnh dạng mà Windows hỗ trợ.
1.1.3. Giao tiếp thiết bị ñồ họa GDI
Khi lập trình trên MS-DOS, ñể giao tiếp với các thiết bị - ñưa dữ liệu ra vùng nhớ màn hình,
cổng máy in chẳng hạn - thì ta phải biết cơ chế của các thiết bị phần cứng tương ứng, rồi ghi dữ
liệu ra thẳng thiết bị.
Thế nhưng, trên Windows, với sự hỗ trợ của hệ ñiều hành, các ứng dụng không cần phải truy
xuất thiết bị vật lý. Dữ liệu ñược xuất ra một ñối tượng thiết bị ảo, gọi là thiết bị ngữ cảnh
(device context), sau ñó thông qua chương trình ñiều khiển thiết bị ñã cài ñặt trên hệ ñiều hành
(tức là các driver của các thiết bị phần cứng), dữ liệu sẽ ñược chuyển ñến các thiết bị vật lý khác
nhau mà người lập trình ứng dụng trên Windows không cần phải biết về chúng.
1.1.4. Quản lý vùng nhớ và tập tin
Với các phiên bản mới của hệ ñiều hành, việc quản lý các vùng nhớ và tập tin của các ứng dụng
trên Windows ngày càng dễ dàng và hiệu quả hơn.
Chúng ta không phải thật sự khó khăn khi cấp phát, truy xuất, giải phóng,… các khối nhớ, vì
ñã có hệ ñiều hành lo giúp. Với cơ chế cấp phát và quản lý ñộng, quản lý vùng nhớ ảo và ánh xạ
vùng nhớ lên hệ thống lưu trữ phụ, việc thao tác các ñối tượng vùng nhớ lớn, phức tạp giờ ñây
chỉ còn là việc gọi các hàm Windows cung cấp và việc tổ chức các cấu trúc dữ liệu phú hợp cho

ứng dụng mà thôi.
1.1.5. Thư viện liên kết ñộng
Trên môi trường MS-DOS, các module của các ñối tượng trong mỗi chương trình chỉ ñược liên
kết tĩnh trong quá trình tạo (build) ứng dụng. Trong khi trên môi trường Windows, các hàm, thư
viện còn có thể ñược gọi khi chương trình ñang thực thi (run-time), gọi là cơ chế liên kết ñộng.
Các tiến trình ñang thực thi có thể cùng chia sẻ các thư viện này, ñiều này giúp giảm thiểu
vùng nhớ và kích thước các tập tin.
Thật ra bản thân hệ ñiều hành Windows là tập hợp các thư viện liên kết ñộng, với ba ñơn vị
chính là Kernel, User, và GDI liên quan ñến các hàm, thủ tục thể hiện các chức năng quản lý các
tiến trình, vùng nhớ, tập tin,… (kernel), giao diện người dùng, các cửa sổ,… (user) và thiết bị ñồ
họa (GDI) và các DLL gắn liền với các ứng dụng khác ñược cài ñặt trên máy tính.
1.2. ỨNG DỤNG WIN32 APPLICATION TRÊN MS VISUAL C++ 6.0
7

Sau khi nắm ñược các ñặc ñiểm chính của các ứng dụng trên môi trường hệ ñiều hành MS
Windows, phần này sẽ giúp các bạn hiểu và xây dựng ứng dụng cụ thể dạng Win32 Application
trên công cụ MS Visual C++ 6.0.
1.2.1. Project ứng dụng Win32 Application
MS Visual C++ 6.0 hỗ trợ lập trình nhiều dạng ứng dụng khác nhau như Win32 Console
Application, Win32 Application, MFC AppWizard, Win32 Dynamic Link Library,… trong ñó
Win32 Application lập trình trực tiếp với các hàm API là dạng mà chúng ta sẽ tìm hiểu trong
môn học này.


Hình 1.1. Tạo lập project dạng Win32 Application

Sử dụng Wizard của Visual C++ 6.0, chúng ta tạo lập project ñầu tiên như sau:
1 Bước 1: Từ menu File, chọn menu item New… Ctrl+N.
2 Bước 2: Trên hộp thoại New chọn dạng Projects Win32 Apllication, gõ tên project (Project
name) và ñường dẫn (Location) cần tạo – xem hình 1.1. Chọn OK.

3 Bước 3: Visual C hỗ trợ cho phép tạo lập một số mẫu project. Ta chọn dạng A typical
“Hello World!” application – xem hình 1.2. Chọn Finish. Với cách chọn này, Visual C++
6.0 phát sinh sẵn một số file code, tài nguyên – kết quả thể hiện trên hình 1.3. Sau khi chọn
OK ñể kết thúc việc tạo project mới, chúng ta sẽ tìm hiểu giao diện của IDE MS Visual C++
6.0 và cách viết chương trình trên công cụ này.
8



Hình 1.2. Chọn project A typical “Hello World!” application

1.2.2. Các thành phần chính trên IDE MS Visual C++ 6.0
ðược xây dựng dựa theo công cụ Visual Workbench, IDE này gồm các cửa sổ, thanh công cụ,
editor có thể cấu hình,… kết hợp hài hòa với nhau giúp các lập trình viên dễ dàng biên soạn
code, tạo lập các tài nguyên, biên dịch, debug lỗi….
9



Hình 1.3. Thông báo sau khi tạo project của Visual C++ 6.0

Nếu ñã từng sử dụng các IDE, có lẽ bạn sẽ dễ dàng ñể hiểu cách tổ chức và hoạt ñộng của
Visual C++ 6.0. Tuy nhiên, nếu mới lập trình trên một IDE như thế này thì bạn cần phải hiểu
project là gì. Một project là một tập hợp các file source có liên hệ với nhau mà trình biên dịch có
thể biên dịch và liên kết ñể tạo các file khả thi dạng Windows hoặc các DLL. Các file source
trong mỗi project thường ñược lưu trữ trong một thư mục riêng biệt. Ngoài ra, một project còn
phụ thuộc vào một số file liên kết như file header, file thư viện… khác.
1 Cửa sổ Workspace
Mặc ñịnh thì cửa sổ bên trái mà chúng ta thấy trên IDE Visual C++ 6.0 là một treeview cho phép
chúng ta chọn các tập tin source code, resource,… ñể soạn thảo.

10

Hình 1.4. Giao diện của MS Visual C++ 6.0



FileView liệt kê các tập tin trong project, tổ chức như cây thư mục phân theo nhóm file chức
năng: các file source code (.c hoặc .cpp), các file header (.h và .hpp), các file resource như icon
(.ico), bitmap (.bmp),…
ResourceView liệt kê các tài nguyên của ứng dụng. Visual C++ 6.0 hỗ trợ các công cụ trực
quan cho phép các lập trình viên thao tác các resource một cách hiệu quả. Khi chọn menu, hộp
thoại,… IDE sẽ thể hiện các editor tương ứng.
ClassView giúp lập trình viên dễ dàng chuyển ñến các lớp ñối tượng (ñặc biệt cho project
MFC), các hàm, các biến trong project.
2 Cửa sổ soạn thảo source code
Visual C++ 6.0 cung cấp một cửa sổ soạn code khá tuyệt vời, hỗ trợ nhiều chức năng khi lập
trình như thể hiện màu chữ theo dạng code, chế ñộ tự ñộng chuyển tab,… và nhất là chức năng
AutoComplete (tự ñộng thể hiện các tên hàm, biến,… ñã ñịnh nghĩa).
3 Cửa sổ thể hiện kết quả build (Output window)
Khi lập trình, việc biên dịch, sửa lỗi,… là thao tác rất quan trọng. Trình biên dịch kiểm tra các lỗi
cú pháp, ngữ nghĩa,… và xuất các thông báo liên quan cho lập trình viên. Căn cứ vào thông báo
lỗi, các lập trình viên có thể lần theo các vết thông báo ñể sửa lại chương trình
4 Các cửa sổ khác trên MS Visual C++ 6.0
11

Ngoài các cửa sổ vừa ñề cập ở trên, Visual C++ 6.0 còn cung cấp các ñối tượng trực quan khác
ñể hỗ trợ các lập trình viên như thanh WizardBar, MenuBar, ToolsBar,… Các cửa sổ trên IDE
này ñều có thể kéo trôi nổi (docking) và sắp xếp theo ý thích của người sử dụng.
1.2.3. Quy trình build ứng dụng
Quy trình build project tạo file khả thi dạng EXE hoặc DLL ñược Visual C++ thực hiện theo hai

công ñoạn chính - xem hình 1.5 - như sau:
Hình 1.5. Quy trình build một project ứng dụng

- Biên dịch (compile) các file source code và resource sang dạng mã trung gian OBJ, RES,…
- Liên kết (link) các file OBJ, RES với các file thư viện Windows và run-time ñể tạo file khả thi.
Với project ñơn giản ñã tạo lập ở trên, chúng ta có thể thực hành xem kết quả build file
BaiTap.exe. Bằng cách chọn chức năng “Build BaiTap.exe F7” từ menu Build, Visual C++
sẽ thực hiện biên dịch và liên kết các file có trong project và tạo các file OBJ, RES, EXE,
tương ứng.
Tuỳ theo dạng build ñược cấu hình cho project (Win32 Release hoặc Win32 Debug), các
file mã phát sinh trong quá trình build sẽ ñược tạo ra trong một thư mục con mặc ñịnh có tên là
Release hoặc Debug - nằm trong thư mục chứa các file nguồn của project.
Nếu tạo lập như ở trên, chúng ta sẽ có các file mã phát sinh trong thư mục
D:\Study\BaiTap\Debug chẳng hạn. ðể ý là khi copy code của một project ñem sang một máy
tính khác ñể build, chúng ta không cần phải copy thư mục này (vì khá lớn)!!!
Hình 1.6. Thể hiện của ứng dụng BaiTap.exe



12

Nếu quá trình build thành công – ñược thông báo trên cửa sổ Output, xem phần 1.2.2. -
chúng ta có thể xem kết quả thực hiện bằng cách chọn chức năng Execute Program (Ctrl+F5).
Kết quả project này thể hiện như ở hình 1.6.
1.3. PHÂN TÍCH SOURCE CODE CỦA PROJECT
Trong project BaiTap dạng Win32 Application ñược tạo như ở trên, file BaiTap.cpp (workspace
FileView) chính là file source chính cài ñặt các thao tác tạo lập và xử lý các chức năng của cửa
sổ ứng dụng này.
Dưới ñây là phần code do MS Visual C++ 6.0 phát sinh, với các chú thích ñược viết lại bằng
tiếng Việt cho dễ hiểu.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

31
32
33
34
35
36
37
38
39
40
41
// BaiTap.cpp : Tập tin cài ñặt chính của ứng dụng BaiTap
#include "stdafx.h"
#include "resource.h"
#define MAX_LOADSTRING 100
// ðịnh nghĩa các biến toàn cục
HINSTANCE hInst; // Instance của ứng dụng
TCHAR szTitle[MAX_LOADSTRING]; // Thể hiện trên thanh tiêu ñề
TCHAR szWindowClass[MAX_LOADSTRING]; // Tên lớp cửa sổ
// ðịnh nghĩa trước các hàm sẽ ñược gọi trong module này
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
// Các biến cục bộ trong hàm WinMain
MSG msg; // Biến kiểu dữ liệu thông ñiệp
HACCEL hAccelTable; // Bảng phím nóng

// Khởi tạo bằng cách nạp các chuỗi từ resource (tài nguyên)
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_BAITAP, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Thực hiện việc khởi tạo ứng dụng
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
Nạp bảng phím nóng từ resource
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_BAITAP);
// Vòng lặp xử lý thông ñiệp của ứng dụng –
xem lại phần 1.1.1

while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
13

42
43
44
45

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

61
62
63
64
65
66
67
68
69
70
71
72
73
74

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Hàm MyRegisterClass() - ðăng ký một lớp cửa sổ.
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex; // Lớp cửa sổ
wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_BAITAP);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_BAITAP;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance,
(LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}

// Hàm InitInstance(HANDLE, int) – Lưu ñịnh danh ứng dụng và tạo cửa sổ
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd; // Biến ñịnh danh cửa sổ
hInst = hInstance; // Lưu ñịnh danh ứng dụng vào biến toàn cục ở trên
// Tạo lập cửa sổ
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
// Hiển thị cửa sổ với dạng hiển thị là nCmdShow
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}
// Hàm WndProc(HWND, unsigned, WORD, LONG)
// Hàm xử lý các thông ñiệp sau của cửa sổ ứng dụng:
// WM_COMMAND - Xử lý các thao tác liên quan ñến menu
// WM_PAINT - Xử lý thao tác
vẽ
lại cửa sổ
// WM_DESTROY - Gởi thông ñiệp kết thúc ứng dụng khi ñóng cửa sổ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
// ðịnh nghĩa các biến cục bộ
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
switch (message)
{
case WM_COMMAND: // Thông ñiệp liên quan tới menu và các control
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Chuyển thao tác ứng với menu item ñược kích hoạt
switch (wmId)
{
14

100


101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

131
132
133
134
135
136
137
138
139
140
141
142
143
144
case IDM_ABOUT:

DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX,
hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT: // Thông ñiệp vẽ lại cửa sổ
hdc = BeginPaint(hWnd, &ps);
RECT rt;
GetClientRect(hWnd, &rt);

DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Xử lý các thông ñiệp gởi cho hộp thoại IDD_ABOUTBOX
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK ||
LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}

Chúng ta sẽ tìm hiểu hai hàm chính luôn phải có trong một chương trình dạng Win32
Application là WinMain và WndProc.
1.3.1. Hàm WinMain
Như ñã giới thiệu ở phần 1.1.1, hệ ñiều hành khởi gọi thực thi một ứng dụng dạng Windows
(Windows-based) thông qua hàm WinMain có dạng:
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, int nCmdShow);
trong ñó:
1 hInstance là con trỏ ñược Windows quản lý xác ñịnh tiến trình ứng dụng ñang thực thi,
gọi là ñịnh danh ứng dụng (handle to instance).
15

2 hPrevInstance là ñịnh danh của tiến trình kế trước của ứng dụng này, thường bằng NULL.
3 lpCmdLine trỏ ñến chuỗi ký tự zero xác ñịnh dòng command line gọi ứng dụng (không
chứa tên chương trình).
4 nCmdShow là tham số xác ñịnh cách thức hiển thị cửa sổ sẽ ñược tạo lập.
Trong một ứng dụng thông thường, hàm WinMain thực hiện các chức năng chính sau.
1 ðịnh nghĩa và ñăng ký một lớp cửa sổ
ðầu tiên của viêc xây
dựng
một ứng dụng Windows là phải ñịnh nghĩa một lớp cửa sổ cho ứng dụng.
Windows cung cấp một cấu trúc
WNDCLASS
(mở rộng là
WNDCLASSEX
) gọi là lớp cửa sổ, lớp
này chứa những thuộc tính tạo thành một cửa sổ.

typedef struct _WNDCLASSEX {
UINT cbSize;

UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;
Sau khi khởi gán giá trị các tham số của ñối tượng lớp cửa sổ, ta dùng hàm RegisterClass
hoặc RegisterClassEx ñể ñăng ký lớp cửa sổ này với hệ thống.
ATOM RegisterClassEx(CONST WNDCLASSEX

*
lpwcx
);
Tuỳ theo cửa sổ ứng dụng muốn thể hiện, ta sẽ xác lập các giá trị khác nhau cho cấu trúc lớp
của sổ ở trên. Ở ñây chúng tôi không trình bày chi tiết các thuộc tính của lớp cửa sổ, sinh viên
cần tham khảo thêm trong MSDN ñể tạo lập các dạng cửa sổ theo ý mình.
Trong các tham số ở trên, cần lưu ý thuộc tính lpfnWndProc. ðây chính là tên hàm xử lý
thông ñiệp của ứng dụng. Trong ví dụ ở trên, tham số này có giá trị là WndProc, ñiều ñó có
nghĩa là với cách tạo lập này thì mọi thao tác xử lý của ứng dụng sẽ ñược viết trong một hàm có
tên là WndProc. Chúng ta sẽ tìm hiểu kỹ hơn về hàm này trong phần 1.3.2.
2 Tạo lập và hiện thị cửa sổ ứng dụng
Sau khi ñăng ký lớp cửa sổ, ở thao tác tiếp theo ta dùng hàm CreateWindow hoặc
CreateWindowEx ñể tạo lập cửa sổ ứng dụng theo cấu trúc cửa sổ ñã ñịnh nghĩa.
16


HWND CreateWindow(
LPCTSTR
lpClassName
,
// Tên lớp cửa sổ ñã ñăng ký

LPCTSTR
lpWindowName
,
// Tên cửa sổ sẽ hiển thị

DWORD
dwStyle
,
// Các kiểu cửa sổ

int
x
,
// Vị trí ngang ban ñầu

int
y
,
// Vị trí dọc ban ñầu

int
nWidth
,

// Chiều rộng ban ñầu
int
nHeight
,
// Chiều cao ban ñầu
HWND
hWndParent
,
// ðịnh danh của cửa sổ cha
HMENU
hMenu
,
// ðịnh danh của menu
HINSTANCE
hInstance
,
// ðịnh danh tiến trình ứng dụng
LPVOID
lpParam

// Dữ liệu gởi vào app khi tạo lập
);
Bằng cách thiết lập các thông số về lớp cửa sổ, tên cửa sổ, kích thước,… ta có thể tạo lập các
cửa sổ khác nhau. Nếu tạo lập thành công, hàm này trả về ñịnh danh của cửa sổ; nếu không, giá
trị trả về bằng NULL.
Các thao tác trên ứng dụng sau này thường tham chiếu ñến biến ñịnh danh cửa sổ vừa ñược
tạo lập. Trong các ứng dụng thông thường – như ở ví dụ trên – thao tác tiếp theo là hiển thị cửa
sổ vừa tạo lập.
BOOL ShowWindow(
HWND

hWnd
,
// ðịnh danh của cửa sổ
int
nCmdShow

// Dạng hiển thị
);
Trong ví dụ ở trên,
nCmdShow
chính là giá trị ñược gởi vào từ hàm WinMain. Tuy nhiên, ta
có thể thay ñổi với các giá trị khác nhau ñể hiển thị cửa sổ dưới nhiều cách thức khác nhau. Sau
ñây là một số dạng hiển thị ñơn giản:
• SW_HIDE: Ẩn cửa sổ này và kích hoạt cửa sổ khác.
• SW_MAXIMIZE: Phóng lớn cửa sổ ra ñầy màn hình.
• SW_MINIMIZE: Thu nhỏ cửa sổ về task bar, ñồng thời kích hoạt cửa sổ ứng dụng kế tiếp
theo thứ tự ñã chọn.
• SW_RESTORE: Hiển thị theo ñúng kích thước ñã tạo lập.
3 Vòng lặp xử lý thông ñiệp
Sau khi cửa sổ ñược hiển thị trên màn hình, chương trình nhận các thao tác của người dùng (từ
bàn phím, mouse,…) hoặc từ các ứng dụng khác, gọi là thông ñiệp. Các thông ñiệp này ñược
Windows quản lý – dưới dạng một hàng ñợi – và chuyển cho ứng dụng qua hàm GetMessage
trong hàm WinMain này.
BOOL GetMessage(
LPMSG
lpMsg
,
// Cấu trúc nhận thông tin thông ñiệp
HWND
hWnd

,
// ðịnh danh của cửa sổ
UINT
wMsgFilterMin
,
// Giá trị thông ñiệp nhỏ nhất
UINT
wMsgFilterMax

// và lớn nhất cần nhận
);
17

Với thông ñiệp nhận ñược, nếu là thông ñiệp phím nóng (accelerator) ta dùng hàm
TranslateAccelerator ñể chuyển các thông tin thành dạng thông ñiệp ứng các thao tác của
menu, control (thông ñiệp này có tên là WM_COMMAND và WM_SYSCOMMAND sẽ ñược học
trong bài nói về menu và control). Tương tự nếu là thông ñiệp về phím ảo (virtual key) ta dùng
hàm TranslateMessage ñể chuyển thành các thông ñiệp ký tự (sẽ ñược học trong bài nói về
mouse và keyboard).
Sau ñó các thông ñiệp nhận ñược này sẽ chuyển cho hàm xử lý thông ñiệp WndProc qua
hàm DispatchMessage.
LRESULT DispatchMessage(
CONST MSG

*
lpmsg

// Thông tin thông ñiệp
);
Trong ví dụ ở trên, msg là một biến cấu trúc kiểu MSG ñược ñịnh nghĩa trong tập tin tiêu ñề

WINUSER.H.
typedef struct tagMSG
{
HWND
hwnd;

UINT
message
;
WPARAM
wParam
;
LPARAM
lParam
;
DWORD
time
;
POINT
pt
;
} MSG, *PMSG;
Kiểu dữ liệu POINT là một kiểu cấu trúc khác, ñược ñịnh nghĩa trong tập tin tiêu ñề
WINDEF.H, và có mô tả :
typedef struct tagPOINT
{
LONG
x
;
LONG

y
;
} POINT, *PPOINT;
Ý nghĩa của các trường trong cấu trúc MSG
1
hwnd
: ðịnh danh của cửa sổ mà thông ñiệp phát sinh.
2
message
: ðịnh danh của thông ñiệp, ví dụ như thông ñiệp phát sinh khi bấm nút chuột
trái là WM_LBUTTONDOWN có giá trị 0x0201.
3
wParam
: Tham số 32-bit chứa các thông tin phụ thuộc vào từng thông ñiệp cụ thể.
4
lParam
: Tham số 32-bit phụ thuộc vào thông ñiệp.
5
time
: Thời gian ñặt thông ñiệp trong hàng ñợi.
6
pt
: Tọa ñộ của chuột khi ñặt thông ñiệp vào hàng ñợi.
Hàm GetMessage sẽ trả về 0 nếu msg chứa thông ñiệp có ñịnh danh WM_QUIT (0x0012),
khi ñó vòng lặp thông ñiệp ngưng và ứng dụng kết thúc. Ngược lại thì hàm sẽ trả về một giá trị
khác 0 với các thông ñiệp khác.
18

1.3.2. Hàm xử lý cửa sổ ứng dụng WndProc
Như ñã nói ở trên, mỗi lần ứng dụng nhận ñược một thông ñiệp trong hàm WinMain thì chuyển

qua cho hàm xử lý WndProc. Và như thế, ta chỉ cần lập trình cho từng thao tác ứng với các
thông ñiệp khác nhau. Ta có cấu trúc hàm WndProc.
LRESULT CALLBACK WndProc(
HWND
hWnd
,
// ðịnh danh cửa sổ nhận thông ñiệp

UINT
message
,
// Giá trị thông ñiệp gởi vào
WPARAM
wParam
,
// Hai giá trị thông tin gởi kèm
LPARAM
lParam
// tuỳ thuộc vào từng thông ñiệp
);
Hàm có kiểu thực hiện là CALLBACK có nghĩa là hàm sẽ ñược gọi lặp ñi lặp mỗi khi có một
tác ñộng từ người dùng hay từ một ứng dụng khác lên cửa sổ. Giá trị trả về có kiểu long
(LRESULT) sẽ do người lập trình viết ứng với mỗi xử lý của các thông ñiệp.
Và như vậy, ñối với các ứng dụng dạng Win32 Application, hầu như chúng ta chỉ cần tìm
hiểu các thông ñiệp, với các giá trị gởi kèm là có thể lập trình ñể xử lý cho các thao tác cần thiết.
Ví dụ ñể xử lý menu, control thì ta cần hiểu về thông ñiệp WM_COMMAND. Các bài học tiếp
theo sẽ giúp sinh viên tìm hiểu tuần tự các ñặc trưng chính của Windows ñồng thời cài ñặt một
vài dạng thông ñiệp liên quan.
1.3.3. Một số lưu ý
ðể kết thúc bài giới thiệu này, chúng tôi xin nêu lên một số lưu ý mà các bạn cần quan tâm khi

học lập trình bằng ngôn ngữ C trên MS Windows.
So với các môn học khác thì môn học này ñòi hỏi các bạn thực hành nhiều. Sau khi nắm
ñược từng ñặc ñiểm chính của các ứng dụng trên Windows, chúng ta cần phải cài ñặt chúng
thông qua một số ví dụ, bài tập – từ ñó sẽ dễ dàng hiểu rõ lại về lý thuyết, và như vậy có thể xây
dựng các ứng dụng khác một cách nhanh chóng.
Thứ hai là vấn ñề áp dụng lý thuyết vào việc xây dựng các ứng dụng cụ thể, việc tham khảo
các tài liệu…Giáo trình này chỉ giúp các bạn nắm ñược cách lập trình trên Windows một cách cơ
bản. Và ñây không phải là tài liệu tham chiếu. Sau khi nắm ñược các ñiểm chính, khi lập trình,
các bạn nên tham chiếu với thư viện MSDN của Microsoft ñể có những hướng dẫn ñầy ñủ nhất.
Và như vậy, nếu ñã làm quen ñược với việc lập trình các ứng dụng trên Windows chỉ với các
hàm API, các bạn có thể tự tìm hiểu ñể có thể lập trình bằng MFC hay một ngôn ngữ nào khác…
(hiện tại bên cạnh việc xây dựng các ứng dụng Windows-based, việc tìm hiểu và xây dựng các
ứng dụng NET-based, ví dụ VB.NET, C#,… là rất cần thiết).
Cuối cùng là một vấn ñề rất cơ bản, cách thức trình bày code khi lập trình. Chúng ta ñã làm
quen với việc lập trình qua nhiều môn học, tuy nhiên theo những gì chúng tôi nhận thấy, phần
ñông sinh viên vẫn rất hạn chế trong việc trình bày source code. Việc trình bày source code
19

không phải là yếu tố quyết ñịnh tính ñúng sai hay hiệu quả của chương trình, nhưng lại là yếu tố
quyết ñịnh kết quả và khả năng lập trình của các lập trình viên. Hầu như rằng các lập trình viên
giỏi luôn trình bày source code của họ rất rõ ràng, logic.
Trong các ứng dụng viết bằng C trên MS Windows, người ta thường dùng cú pháp Hungary
(Hungarian Notation) ñể ñặt tên biến, hàm,… trong chương trình. Các biến thường bắt ñầu bằng
các ký tự chữ thường thể hiện cho kiểu dữ liệu sau ñó là tên biến, như nCmdLine là một biến kiểu
số nguyên int (number), hwndEdit là một biến ñịnh danh (handle) của cửa sổ edit kiểu HWND.
Về tên biến và tên hàm sẽ viết hoa ký tự ñầu tiên trong mỗi từ (word), các từ viết liền nhau. Ví
dụ biến szWindowClass, hàm InitInstance, hàm CreateWindow
Tương tự, việc canh lề các dòng code cũng cần lưu ý. Bằng cách ñặt cùng lề cho các dòng
lệnh cùng cấp, ta dễ dàng tìm ra các lệnh nào liên hệ với nhau như thế nào,… Và như vậy rất dễ
dàng khi chỉnh sửa các lỗi về cú pháp. Ví dụ như ở chương trình mẫu ở trên, ở hàm About (dòng

127 ñến 144) việc rẽ nhánh các thông ñiệp (lệnh switch ở dòng 130) cùng cấp với lệnh return
(dòng 143), các trường hợp (case) của các thông ñiệp thì cùng cấp (dòng 132, 134)
1.4. TÓM TẮT
Trong bài học ñầu tiên này, chúng ta ñã hiểu ñược thế nào là một ứng dụng ñược lập trình trên
Windows, so với một ứng dụng dạng console (MS-DOS), trong ñó tập trung giới thiệu về cấu
trúc một project dạng Win32 Application gồm hai hàm chính WinMain (1.3.1) và WndProc
(1.3.2).
Chúng ta cũng ñã tìm hiểu về cách thức tạo lập dạng project này trên IDE MS Visual C++
6.0 (1.2.1), phân tích giao diện IDE (1.2.2) và quy trình build tạo file khả thi của project (1.2.3).
Phần lý thuyết chung của bài học (1.1) trình bày các ñặc ñiểm chính của MS Windows và các
ứng dụng trên hệ ñiều hành này, gồm cơ chế xử lý thông ñiệp, lập trình giao diện ñồ họa GUI,
lập trình giao tiếp thiết bị ñồ họa GDI, cơ chế quản lý vùng nhớ ñộng và thư viện liên kết ñộng
DLL, trong ñó xử lý thông ñiệp (liên quan tới hàm vòng lặp nhận thông ñiệp trong hàm WinMain
rồi chuyển cho hàm WndProc xử lý) là quan trọng nhất.
Ở các bài học tiếp theo chúng ta sẽ tìm hiểu lần lượt các ñặc ñiểm nêu trên qua các kiến thức
lý thuyết cơ bản, và áp dụng trên các ví dụ cụ thể.
1.5. CÂU HỎI ÔN TẬP – BÀI TẬP
1.5.1. Trình bày các ñặc ñiểm chính của các ứng dụng trên MS Windows? Các ñặc ñiểm này
khác với trên môi trường MS-DOS như thế nào?
1.5.2. Cho biết quy trình biên dịch và liên kết ñể tạo file khả thi dạng Win32 Application. Quy
trình này khác quy trình build thông thường trên MS-DOS như thế nào?
1.5.3. Hàm WinMain của một ứng dụng thông thường dạng Win32 Application gồm những thao
tác gì? Việc gọi vòng lặp thông ñiệp có ý nghĩa như thế nào?
20

1.5.4. Tạo lập project Win32 Application theo ba dạng khác nhau: “An empty project.”, “A
simple Win32 Application.” và “A typical “Hello World!” application.” - xem bước 3 phần 1.2.1.
Tìm hiểu cấu trúc thể hiện khác nhau của các project trên cửa sổ Workspace, cũng như các file
ñược tạo lập theo từng chọn lựa (trên thư mục chứa project tương ứng).
1.5.5. Với project “A typical “Hello World!” application.”, liệt kê các kiểu dữ liệu và các hàm

trong ứng dụng. Sau ñó tìm hiểu về chúng trong MSDN.
21

Baøi 2
GIAO DIỆN ðỒ HỌA NGƯỜI DÙNG
Như ñã giới thiệu trong bài học ñầu tiên, giao diện ñồ họa người dùng (GUI – Graphical User
Interface) chính là ñặc ñiểm làm cho các ứng dụng trên MS Windows trở nên thân thiện, dễ sử
dụng… Và cũng chính nhờ ñặc ñiểm này mà các chương trình trên máy tính trở nên gần gũi và
thực tế hơn rất nhiều so với các ứng dụng trước ñây trên MS-DOS.
Bài học này sẽ giúp các bạn tạo lập cũng như lập trình xử lý cho các ñối tượng giao diện
quen thuộc trên Windows như thanh trình ñơn (menu), các ñối tượng ñiều khiển (control) như
button, edit, combo box,… trên môi trường công cụ MS Visual C++ 6.0.
2.1. CƠ CHẾ LẬP TRÌNH SỬ DỤNG TÀI NGUYÊN
Khi sử dụng các ứng dụng trên Windows, chắc chắn các bạn dễ dàng nhận ra chúng có cùng
những ñặc trưng giao diện cũng như cách xử lý các ñối tượng giao diện này. Ví dụ, khi muốn
thực hiện một công việc nào ñó, người ta thường chọn theo từng nhóm các thao tác ñã ñược ñịnh
trước trên một thanh menu; khi thao tác các phím nóng người ta có thể dùng tổ hợp Alt + ký tự
gạch dưới của một ñối tượng menu item, button, static,… nào ñó.
Việc thể hiện giao diện giống nhau cũng như có cùng cơ chế xử lý của các ứng dụng trên
Windows là do hệ ñiều hành quyết ñịnh. Chúng ñược ñịnh nghĩa trong các tập tin liên kết của hệ
thống (USER.EXE - 16 bits và USER32.DLL - 32 bits). Dựa trên ñặc ñiểm này, các công cụ
soạn thảo và biên dịch ñược xây dựng sao cho các lập trình viên khi lập trình chỉ cần thực hiện
các thao tác khá ñơn giản là ñưa thông tin các ñối tượng cần tạo lập theo các mẫu (template) ñã
ñược ñịnh nghĩa trước. Cơ chế này gọi là lập trình sử dụng tài nguyên (resource-based
programming).
2.1.1. Cửa sổ workspace ResourceView
Trong các project ứng dụng trên Windows viết bằng C, tài nguyên ñược ñịnh nghĩa trong các tập
tin RC (resource). Với sự hỗ trợ trực quan của MS Visual C++ 6.0, ta dễ dàng xem và thao tác
các resource này trong workspace ResourceView.


22


Hình 2.1. Tạo lập resource trên môi trường Visual C++ 6.0
Bằng cách chọn tập tin BaiTap.rc trong workspace FileView hoặc click chọn vào
ResourceView của project BaiTap trong bài 1, các tài nguyên của project này sẽ thể hiện như
trong hình 2.1.
ðể thao tác resource nào ta chỉ việc click chọn vào ñối tượng ấy trên ResourceView. Khi ñó
mặc ñịnh Visual C++ 6.0 sẽ tự ñộng mở cửa sổ resource editor trực quan tương ứng ñể ta thêm,
bớt, hoặc chỉnh sửa.
2.1.2. Cấu trúc resource dạng văn bản và editor trực quan
Thật ra, tài nguyên ñược ñịnh nghĩa theo các ñịnh dạng văn bản (text) cho sẵn trong tập tin RC.
Và khi ta mở các tập tin này, Visual C++ 6.0 mới nạp dữ liệu text này và thể hiện giao diện trực
quan cho ta dễ thao tác.


23

Hình 2.2. Chọn mở xem tập tin resource dưới dạng text
Do ñó, trong bài học, chúng ta chủ yếu tìm hiểu cách thao tác trực quan. Bên cạnh ñó, chúng
ta cũng cần hiểu cơ bản về cách tổ chức văn bản của các resource ñể có thể chỉnh sửa khi dữ liệu
không chính xác và Visual C++ 6.0 không thể nạp ñược.
Khi chọn xem tập tin RC dưới dạng text (Open as Text)- xem hình 2.2, Visual C++ 6.0 sẽ
thể hiện toàn bộ nội dung văn bản của tập tin này ở cửa sổ soạn thảo (text editor). Với project
BaiTap ta có nội dung tập tin BaiTap.rc như sau:
1
2
3
4
5

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47
48
//Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE 9, 1
#pragma code_page(1252)

#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_BAITAP ICON DISCARDABLE "BaiTap.ICO"
IDI_SMALL ICON DISCARDABLE "SMALL.ICO"
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDC_BAITAP MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", IDM_EXIT
END
POPUP "&Help"
BEGIN
MENUITEM "&About ", IDM_ABOUT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDC_BAITAP ACCELERATORS MOVEABLE PURE
BEGIN

"?", IDM_ABOUT, ASCII, ALT
24

49

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103


"/", IDM_ABOUT, ASCII, ALT

END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "System"
BEGIN
ICON IDI_BAITAP,IDC_MYICON,14,9,16,16
LTEXT "BaiTap Version 1.0",IDC_STATIC,49,10,119,8,SS_NOPREFIX
LTEXT "Copyright (C) 2003",IDC_STATIC,49,20,119,8
DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""windows.h""\r\n"
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""resource.h""\r\n"
"\0"
END

3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDC_BAITAP "BAITAP"
IDS_APP_TITLE "BaiTap"
IDS_HELLO "Hello World!"
END
#endif
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
}
Như ñã nói, chúng ta thao tác các ñối tượng resource bằng công cụ trực quan. Khi ñó, Visual
C++ 6.0 tự ñộng phát sinh các dữ liệu text tương ứng. ðối với project bài tập này, dữ liệu của
Accelerator IDC_BAITAP (xem hình 2.1) tương ứng ñoạn text từ dòng 40 ñến 50 ở trên,
25


Dialog IDD_ABOUTBOX tương ứng ñoạn text từ dòng 55 ñến 64, v.v…
Ngoài các macro ñịnh nghĩa các dạng mẫu resource - ví dụ DIALOG là macro cho biết
resource là hộp thoại, LTEXT là macro của control static text canh lề trái trên hộp thoại,… -
trong nội dung tập tin RC ở trên còn có các giá trị ñược ñịnh nghĩa xác ñịnh ñịnh danh
(identifier) của các ñối tượng tài nguyên. ðây là ñiểm cần chú ý khi tạo lập và chỉnh sửa các
resource. Trong phần tìm hiểu các ñối tượng resource cụ thể như menu, control, … ở sau, chúng
ta sẽ nói lại về vấn ñề này. Chúng ñược ñịnh nghĩa (define) thay cho các số nguyên ñể người
dùng dễ lập trình. Khi viết code, ví dụ trong phần xử lý menu trong thông ñiệp
WM_COMMAND của project bài tập, lập trình viên xử lý menu item thông qua giá trị ñã ñịnh
nghĩa này (IDM_EXIT, IDM_ABOUT) mà không quan tâm tới giá trị số nguyên cụ thể của nó;
trong khi ñể quản lý các menu item thì hệ thống quản lý thông qua giá trị số của chúng.

Hình 2.3. Chọn xem thông tin của tài nguyên
Trong project Win32 Application mà Visual C++ 6.0 tạo ra thì các giá trị này ñược phát sinh
ñồng thời trong tập tin resource.h khi ta thao tác các resource tương ứng. Nội dung tập tin
resource.h của project BaiTap như sau:
26


Hình 2.4. Xem thông tin về tập tin resource.h

1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by BAITAP.RC
//
#define IDR_MAINFRAME 128
#define IDD_BAITAP_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDS_APP_TITLE 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDS_HELLO 106
#define IDI_BAITAP 107

#define IDI_SMALL 108
#define IDC_BAITAP 109
#define IDC_MYICON 2
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 129
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif
Các giá trị này ñược ñịnh nghĩa thay thế cho các macro ñược phát sinh khác nhau cho các
project khác nhau. Hơn nữa, chúng luôn là các giá trị khác nhau cho các macro khác nhau. Và vì
thế nếu chúng ta soạn thảo chúng dưới dạng text, cần phải chú ý ñể tránh trường hợp trùng lặp
giá trị, bởi trong các trường hợp này khi cài ñặt code cho thao tác các ñối tượng liên quan có thể
dẫn ñến các xử lý tương ứng không chính xác.
27


Hình 2.5. Macro và giá trị của tài nguyên ñã ñịnh nghĩa
Ngoài ra, ñể xem các macro ñược ñịnh nghĩa của các tài nguyên trong tập tin BaiTap.rc ta
có thể xem trực quan qua sự hỗ trợ của MS Visual C++ 6.0. Bằng cách click chuột phải (mặc
ñịnh) lên “BaiTap resources” trên ResourceView – hình 2.3. – ta chọn tiếp “Resouce
Includes…” ñể xem các thông tin về tập tin resource.h – hình 2.4, hoặc chọn “Resource
Symbols…” ñể xem giá trị các macro ñã ñược ñịnh nghĩa – hình 2.5.

2.2. TRÌNH ðƠN

Trong hầu hết các ứng dụng, thao tác của người dùng thường thể hiện theo từng nhóm công việc.
ðể tiện việc chọn lựa công việc, chúng ta có thể lần theo một cây phân cấp gọi là menu (trình
ñơn). Nhờ có menu, giao tiếp giữa người dùng với ứng dụng trở nên dễ dàng, ñơn giản thông qua
lựa chọn trực quan các mục chọn gọi là menu item.
MS Windows hỗ trợ một số dạng thể hiện menu dựa trên các yêu cầu thao tác khác nhau của
người dùng như shortcut menu (thường thể hiện khi người dùng rightclick lên cửa sổ ứng
dụng), popup menu (thanh menu thông thường dưới thanh tiêu ñề ở các ứng dụng), system
menu (menu hệ thống của cửa sổ ứng dụng, gằn liền các thao tác như Maximize, Minimize,
Close,…).
Trong phạm vi môn học, chúng ta chỉ tìm hiểu cơ bản về menu với chức năng ñơn giản nhất
là nhận thao tác của người dùng (mà không xử lý thể hiện giao diện phức tạp với font chữ, icon
ảnh,…) thông qua thanh menu thông thường – xem hình 2.6.
Các item của thanh menu hiển thị ngay dưới thanh tiêu ñề của ứng dụng tạo thành thanh
menu chính (top-level menu). Trên menu chính, chúng ta có một hay nhiều item liệt kê – ñại diện
cho nhóm chức năng - gọi là drop-down menu (thả xuống) hay popup menu (bung lên). Ứng với
28

mỗi item liệt kê như vậy, chúng ta lại có thể cấu trúc như ở menu chính, nghĩa là có thể tạo thêm
các popup cấp 2 (rồi tương tự sau ñó là cấp 3, 4,…) và các item con khác. Chú ý là chúng ta chỉ
nhận và xử lý thao tác của các menu item mà thôi.

Hình 2.6. Thanh menu của MS Visual C++ 6.0

2.2.1. Tạo mẫu tài nguyên menu trên công cụ trực quan
Có hai cách chính ñể tạo lập một tài nguyên menu trong tập tin resource (.RC).
1 Cách 1: Mở tập tin .RC dưới dạng text và sau ñó tiến hành tạo menu bằng cách gõ các dòng
lệnh theo cấu trúc của menu trong tập tin RC. Thông thường, cách này ít dùng vì khá phức
tạp, khó nhớ và khó quản lý các giá trị chỉ danh của các item mà ta phải ñịnh nghĩa. Chúng ta
sẽ không tìm hiểu về cách thao tác này trong môn học, tuy nhiên, các bạn cần tham khảo cấu
trúc có sẵn của chúng sau khi tạo lập trực quan (ở cách 2) ñể có thể xử lý khi có lỗi về phần

code tương ứng.
2 Cách 2: Sử dụng công cụ tạo lập và thao tác tài nguyên trực quan của MS Visual C++ 6.0.
Bằng cách chọn tài nguyên của project qua workspace ResourceView như ở hình 2.1, rồi
chọn mục Menu ñể thao tác. Ta có thể chọn một menu ñã có sẵn ñể sửa lại, hoặc Insert
Menu ñể thêm menu mới (Visual C++ 6.0 sẽ tạo một menu với ID của menu tự phát sinh. Ta
có thể click chuột phải trên menu mới tạo, chọn Properties ñể thay ñổi các thông số cần thiết
– xem hình 2.7).

×