intTypePromotion=1

Giáo trình Lập trình C trên Windows: Phần 1 - Nguyễn Đình Quyên, Mai Xuân Hùng (đồng biên soạn)

Chia sẻ: Hoa La Hoa | Ngày: | Loại File: PDF | Số trang:70

0
137
lượt xem
58
download

Giáo trình Lập trình C trên Windows: Phần 1 - Nguyễn Đình Quyên, Mai Xuân Hùng (đồng biên soạn)

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Giáo trình Lập trình C trên Windows gồm 6 bài, được chia thành hai phần. Phần 1 giới thiệu đến bạn đọc nội dung từ bài 1 đến bài 3 về các nội dung sau: Tổng quan về lập trình Windows, giao diện đồ họa người dùng và hộp hội thoại.

Chủ đề:
Lưu

Nội dung Text: Giáo trình Lập trình C trên Windows: Phần 1 - Nguyễn Đình Quyên, Mai Xuân Hùng (đồng biên soạn)

  1. 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 5
  2. 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 6
  3. 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. 7
  4. 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…. 8
  5. 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. 9
  6. 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 10
  7. 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 11
  8. 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 // BaiTap.cpp : Tập tin cài ñặt chính của ứng dụng BaiTap 2 #include "stdafx.h" 3 #include "resource.h" 4 #define MAX_LOADSTRING 100 5 // ðịnh nghĩa các biến toàn cục 6 HINSTANCE hInst; // Instance của ứng dụng 7 TCHAR szTitle[MAX_LOADSTRING]; // Thể hiện trên thanh tiêu ñề 8 TCHAR szWindowClass[MAX_LOADSTRING]; // Tên lớp cửa sổ 9 // ðịnh nghĩa trước các hàm sẽ ñược gọi trong module này 10 ATOM MyRegisterClass(HINSTANCE hInstance); 11 BOOL InitInstance(HINSTANCE, int); 12 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 13 LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); 14 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 15 LPSTR lpCmdLine, int nCmdShow) 16 { 17 // Các biến cục bộ trong hàm WinMain 18 MSG msg; // Biến kiểu dữ liệu thông ñiệp 19 HACCEL hAccelTable; // Bảng phím nóng 20 // Khởi tạo bằng cách nạp các chuỗi từ resource (tài nguyên) 21 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 22 LoadString(hInstance, IDC_BAITAP, szWindowClass, MAX_LOADSTRING); 23 MyRegisterClass(hInstance); 24 // Thực hiện việc khởi tạo ứng dụng 25 if (!InitInstance (hInstance, nCmdShow)) 26 { 27 return FALSE; 28 } 29 Nạp bảng phím nóng từ resource 30 hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_BAITAP); 31 // Vòng lặp xử lý thông ñiệp của ứng dụng – xem lại phần 1.1.1 32 while (GetMessage(&msg, NULL, 0, 0)) 33 { 34 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 35 { 36 TranslateMessage(&msg); 37 DispatchMessage(&msg); 38 } 39 } 40 return msg.wParam; 41 } 12
  9. 42 // Hàm MyRegisterClass() - ðăng ký một lớp cửa sổ. 43 ATOM MyRegisterClass(HINSTANCE hInstance) 44 { 45 WNDCLASSEX wcex; // Lớp cửa sổ 46 wcex.cbSize = sizeof(WNDCLASSEX); 47 wcex.style = CS_HREDRAW | CS_VREDRAW; 48 wcex.lpfnWndProc = (WNDPROC)WndProc; 49 wcex.cbClsExtra = 0; 50 wcex.cbWndExtra = 0; 51 wcex.hInstance = hInstance; 52 wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_BAITAP); 53 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 54 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 55 wcex.lpszMenuName = (LPCSTR)IDC_BAITAP; 56 wcex.lpszClassName = szWindowClass; 57 wcex.hIconSm = LoadIcon(wcex.hInstance, 58 (LPCTSTR)IDI_SMALL); 59 return RegisterClassEx(&wcex); 60 } 61 // Hàm InitInstance(HANDLE, int) – Lưu ñịnh danh ứng dụng và tạo cửa sổ 62 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 63 { 64 HWND hWnd; // Biến ñịnh danh cửa sổ 65 hInst = hInstance; // Lưu ñịnh danh ứng dụng vào biến toàn cục ở trên 66 // Tạo lập cửa sổ 67 hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, 68 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); 69 if (!hWnd) 70 { 71 return FALSE; 72 } 73 // Hiển thị cửa sổ với dạng hiển thị là nCmdShow 74 ShowWindow(hWnd, nCmdShow); 75 UpdateWindow(hWnd); 76 return TRUE; 77 } 78 // Hàm WndProc(HWND, unsigned, WORD, LONG) 79 // Hàm xử lý các thông ñiệp sau của cửa sổ ứng dụng: 80 // WM_COMMAND - Xử lý các thao tác liên quan ñến menu 81 // WM_PAINT - Xử lý thao tác vẽ lại cửa sổ 82 // WM_DESTROY - Gởi thông ñiệp kết thúc ứng dụng khi ñóng cửa sổ 83 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, 84 LPARAM lParam) 85 { 86 // ðịnh nghĩa các biến cục bộ 87 int wmId, wmEvent; 88 PAINTSTRUCT ps; 89 HDC hdc; 90 TCHAR szHello[MAX_LOADSTRING]; 91 LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); 92 switch (message) 93 { 94 case WM_COMMAND: // Thông ñiệp liên quan tới menu và các control 95 wmId = LOWORD(wParam); 96 wmEvent = HIWORD(wParam); 97 // Chuyển thao tác ứng với menu item ñược kích hoạt 98 switch (wmId) 99 { 13
  10. 100 case IDM_ABOUT: 101 DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, 102 hWnd, (DLGPROC)About); 103 break; 104 case IDM_EXIT: 105 DestroyWindow(hWnd); 106 break; 107 default: 108 return DefWindowProc(hWnd, message, wParam, lParam); 109 } 110 break; 111 case WM_PAINT: // Thông ñiệp vẽ lại cửa sổ 112 hdc = BeginPaint(hWnd, &ps); 113 RECT rt; 114 GetClientRect(hWnd, &rt); 115 DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER); 116 EndPaint(hWnd, &ps); 117 break; 118 case WM_DESTROY: 119 PostQuitMessage(0); 120 break; 121 default: 122 return DefWindowProc(hWnd, message, wParam, lParam); 123 } 124 return 0; 125 } 126 // Xử lý các thông ñiệp gởi cho hộp thoại IDD_ABOUTBOX 127 LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, 128 LPARAM lParam) 129 { 130 switch (message) 131 { 132 case WM_INITDIALOG: 133 return TRUE; 134 case WM_COMMAND: 135 if (LOWORD(wParam) == IDOK || 136 LOWORD(wParam) == IDCANCEL) 137 { 138 EndDialog(hDlg, LOWORD(wParam)); 139 return TRUE; 140 } 141 break; 142 } 143 return FALSE; 144 } 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). 14
  11. 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. 15
  12. 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 ); 16
  13. 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. 17
  14. 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 18
  15. 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? 19
  16. 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. 20
  17. 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. 21
  18. 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. 22
  19. 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 //Microsoft Visual C++ generated resource script. 2 // 3 #include "resource.h" 4 #define APSTUDIO_READONLY_SYMBOLS 5 ///////////////////////////////////////////////////////////////////////////// 6 // 7 // Generated from the TEXTINCLUDE 2 resource. 8 // 9 #define APSTUDIO_HIDDEN_SYMBOLS 10 #include "windows.h" 11 #undef APSTUDIO_HIDDEN_SYMBOLS 12 ///////////////////////////////////////////////////////////////////////////// 13 #undef APSTUDIO_READONLY_SYMBOLS 14 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 15 #ifdef _WIN32 16 LANGUAGE 9, 1 17 #pragma code_page(1252) 18 #endif //_WIN32 19 ///////////////////////////////////////////////////////////////////////////// 20 // 21 // Icon 22 // 23 // Icon with lowest ID value placed first to ensure application icon 24 // remains consistent on all systems. 25 IDI_BAITAP ICON DISCARDABLE "BaiTap.ICO" 26 IDI_SMALL ICON DISCARDABLE "SMALL.ICO" 27 ///////////////////////////////////////////////////////////////////////////// 28 // 29 // Menu 30 // 31 IDC_BAITAP MENU DISCARDABLE 32 BEGIN 33 POPUP "&File" 34 BEGIN 35 MENUITEM "E&xit", IDM_EXIT 36 END 37 POPUP "&Help" 38 BEGIN 39 MENUITEM "&About ...", IDM_ABOUT 40 END 41 END 42 ///////////////////////////////////////////////////////////////////////////// 43 // 44 // Accelerator 45 // 46 IDC_BAITAP ACCELERATORS MOVEABLE PURE 47 BEGIN 48 "?", IDM_ABOUT, ASCII, ALT 23
ADSENSE
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2