Bài giảng Lập trình Windows (Phần 2)

1. Khái niệm và vai trò của CSDL Registry

1.1 Các khóa, các hive

Registry là nơi lưu trữ tất cả các các loại cấu trúc dữ liệu. Cấu hình hệ thống Windows,

cấu hình phần cứng máy tính, cấu hình thông tin về các chương trình ứng dụng dựa trên

Win32, và các thiết lập người dùng khác đều được lưu trong Registry.

Ví dụ, bất cứ một phần cứng máy tính nào thay đổi đều làm chức năng Plug and Play

(Cắm và chạy) khởi tạo ngay và làm thay đổi luôn cấu hình trong Registry.

Registry lưu trữ tất cả các thiết lập về cấu trúc bộ nhớ, phần cứng, thiết bị ngoại vi, và

các thành phần liên quan đến mạng. Bạn sẽ tìm thấy ở đó nhiều hơn những thiết lập cần thiết

trong các tệp khởi tạo ban đầu

Từ Win98 về sau, Windows có sử dụng Registry Checker để tự quét Registry, nếu

không thấy gì, nó tự lưu backup một lần trong ngày, nếu tìm thấy lỗi sẽ sửa. có thể sửa bằng

cách thay thế bản Registry đã backup gần nhất còn tốt. Registry Checker tối ưu hoá và nén

file backup thành công mỗi lần khởi động máy. Nó còn làm một loạt các việc linh tinh như

loại bỏ những khoảng trống không dùng trong Registry, tối ưu hoá.Bài giảng môn học:

Các tệp Registry của Windows.

Registry hiện tại bao gồm 3 tệp chính:

1. Tệp USER.DAT

Dùng để lưu trữ những xác lập người sử dụng đối với các phần mềm.

2. Tệp SYSTEM.DAT

Dùng để lưu trữ những xác lập liên quan tới máy tính và phần cứng.

3. Tệp Policy.pol

System policies được thiết kế để chuẩn bị cho việc ghi đè bất cứ thiết lập đã được chứa

trong 2 thành phần registry khác nhau.

System policies có thể chứa dữ liệu bổ sung đặc trưng tới mạng hay môi trường tổ hợp

như đã được cài đặt bởi network administrator. Bản thân System policies cũng đã được chứa

trong tệp Policy.pol. Không như SYSTEM.DAT và USER.DAT, Policy.pol không phải là

thành phần bắt buộc của phần cài đặt Windows.

Các khóa chính trong một CSDL Registry:

+ HKEY_LOCAL_MACHINE chứa các thông tin về cấu hình vật lý của hệ thống cùng

với các phần mềm đã được cài đặt trên hệ thống.

+ HKEY_USERS: chứa các thông tin cấu hình của tài khoản người dùng

+ HKEY_CURRENT_CONFIG: chứa các thông tin thiết lập của hệ thống hiện tại

chẳng hạn như độ phân giải màn hình hay font chữ.

+ HKEY_CLASS_ROOT: chứa các thông tin ánh xạ từ các kiểu file sang các ứng dụng

mở chúng.

HKEY_CURRENT_USER: chứa các thông tin về các tài khoản trên hệ thống, chẳng

hạn như các biến môi trường, các máy in và các tùy chọn ứng dụng khác.

pdf 49 trang yennguyen 3960
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Lập trình Windows (Phần 2)", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Bài giảng Lập trình Windows (Phần 2)

Bài giảng Lập trình Windows (Phần 2)
Bài giảng môn học: Lâp̣ triǹh Windows 
41 
Chƣơng 3: Hê ̣thống CSDL Registry 
1. Khái niệm và vai trò của CSDL Registry 
1.1 Các khóa, các hive 
Registry là nơi lƣu trữ tất cả các các loại cấu trúc dữ liệu. Cấu hình hệ thống Windows, 
cấu hình phần cứng máy tính, cấu hình thông tin về các chƣơng trình ứng dụng dựa trên 
Win32, và các thiết lập ngƣời dùng khác đều đƣợc lƣu trong Registry. 
Ví dụ, bất cứ một phần cứng máy tính nào thay đổi đều làm chức năng Plug and Play 
(Cắm và chạy) khởi tạo ngay và làm thay đổi luôn cấu hình trong Registry. 
Registry lƣu trữ tất cả các thiết lập về cấu trúc bộ nhớ, phần cứng, thiết bị ngoại vi, và 
các thành phần liên quan đến mạng. Bạn sẽ tìm thấy ở đó nhiều hơn những thiết lập cần thiết 
trong các tệp khởi tạo ban đầu 
Từ Win98 về sau, Windows có sử dụng Registry Checker để tự quét Registry, nếu 
không thấy gì, nó tự lƣu backup một lần trong ngày, nếu tìm thấy lỗi sẽ sửa... có thể sửa bằng 
cách thay thế bản Registry đã backup gần nhất còn tốt. Registry Checker tối ƣu hoá và nén 
file backup thành công mỗi lần khởi động máy. Nó còn làm một loạt các việc linh tinh nhƣ 
loại bỏ những khoảng trống không dùng trong Registry, tối ƣu hoá... 
Bài giảng môn học: Lâp̣ triǹh Windows 
42 
Các tệp Registry của Windows. 
Registry hiện tại bao gồm 3 tệp chính: 
1. Tệp USER.DAT 
Dùng để lƣu trữ những xác lập ngƣời sử dụng đối với các phần mềm. 
2. Tệp SYSTEM.DAT 
Dùng để lƣu trữ những xác lập liên quan tới máy tính và phần cứng. 
3. Tệp Policy.pol 
System policies đƣợc thiết kế để chuẩn bị cho việc ghi đè bất cứ thiết lập đã đƣợc chứa 
trong 2 thành phần registry khác nhau. 
System policies có thể chứa dữ liệu bổ sung đặc trƣng tới mạng hay môi trƣờng tổ hợp 
nhƣ đã đƣợc cài đặt bởi network administrator. Bản thân System policies cũng đã đƣợc chứa 
trong tệp Policy.pol. Không nhƣ SYSTEM.DAT và USER.DAT, Policy.pol không phải là 
thành phần bắt buộc của phần cài đặt Windows. 
Các khóa chính trong một CSDL Registry: 
+ HKEY_LOCAL_MACHINE chứa các thông tin về cấu hình vật lý của hệ thống cùng 
với các phần mềm đã đƣợc cài đặt trên hệ thống. 
+ HKEY_USERS: chứa các thông tin cấu hình của tài khoản ngƣời dùng 
+ HKEY_CURRENT_CONFIG: chứa các thông tin thiết lập của hệ thống hiện tại 
chẳng hạn nhƣ độ phân giải màn hình hay font chữ. 
+ HKEY_CLASS_ROOT: chứa các thông tin ánh xạ từ các kiểu file sang các ứng dụng 
mở chúng. 
HKEY_CURRENT_USER: chứa các thông tin về các tài khoản trên hệ thống, chẳng 
hạn nhƣ các biến môi trƣờng, các máy in và các tùy chọn ứng dụng khác. 
1.2 Các kiểu dữ liệu 
Lời khuyên của Microsoft về những công cụ xử lý registry 
Bài giảng môn học: Lâp̣ triǹh Windows 
43 
Phƣơng pháp Thiết lập 
Control Panel 
Phần lớn thiết lập hệ thống SYSTEM. Ví dụ bạn sử dụng Display 
Properties để sửa các thành phần của mục appearance 
System Policy Editor Thiết lập ngƣời dùng, vài thiết lập hệ thống. 
Các chƣơng trình tiện ích thứ 3 Thiết lập chi tiết ứng dụng 
Bạn có thể đã sử dụng Registry Editor để thay đổi Registry bằng tay. Tôi thƣờng dùng 
Norton Registry Editor vì nó còn có thêm chức năng khác, ví dụ nhƣ tìm và thay thế đối với 
các thành phần của Registry. 
Từ các phần mềm Registry Editor trên, ta nhận thấy registry đƣợc bố trí thành các 
nhánh lớn. Tại mỗi nhánh có các khoá SUBKEY. Tại các SUBKEY dữ liệu đƣợc lƣu ở các 
dạng: 
1. String (Dạng chuỗi) 
2. Numeric (Dạng số) 
3. Binary (Dạng nhị phân) 
4. Expanded String (Dạng chuỗi mở rộng) 
5. MultiString (Dạng chuỗi tổng hợp) 
(Nếu bạn dùng Registry Editor - REGEDIT. EXE thì sẽ gọi tên khác là DWORD) 
2. Quản lý CSDL Registry 
Khi lập trình đối với Registry, bạn phải thực hiện hết sức thận trọng, sao lƣu các tệp này 
thƣờng xuyên để tránh lỗi đáng tiếc, phải mất công cài lại thì cũng rất mất thời gian.Sử dụng 
các hàm API đối với Registry cũng xin hết sức thận trọng. 
2.1 Thay đổi khóa 
Để thay đổi giá trị của một khóa trong CSDL Registry chúng ta sử dụng hàm LONG 
RegSetValueEx(HKEY hKey, LPCTSTR lpValueName, DWORD reserved, DWORD 
dwType, CONST BYTE * lpData, CONST cbData). 
2.2 Thêm mới khóa 
Để làm việc với các khóa trong CSDL Registry đầu tiên chúng ta sẽ quan tâm tới các 
hàm thêm khóa mới: LONG RegOpenKeyEx(HKEY hKey, LPCTSTR lpSubKey, DWORD 
ulOptions, REGSAM samDesired, PHKEY phkResult). Trong đó tham số thứ nhất là handle 
trỏ tới khóa đang mở, tham số phkResult trỏ tới một biến có kiểu HKEY cho khóa có thể mớ 
mới, lpSubKey là tên của subkey mà chúng ta muốn mở, thông thƣờng có thể là một đƣờng 
dẫn chăng hạn nhƣ “Microsoft\WindowsNT\CurrentVersion”. Giá trị NULL cho biến này có 
nghĩa là một khóa bằng giá trị hKey sẽ đƣợc sinh ra. Biến ulOptions là biến dự trữ và có giá 
trị bằng 0. Biến samDesired là mặt nạ truy cập mô tả giá trị bảo mật cho khóa mới, có thể là 
kết hợp của các giá trị hằng số KEY_ALL_ACCESS, KEY_WRITE, 
KEY_QUERY_VALUE, KEY_ENUMERATE_SUBKEYS. Giá trị trả về của hàm thƣờng là 
ERROR_SUCCESS. Cũng có thể dùng hàm LONG RegCreateKeyEx( HKEY hKey, 
LPCTSTR lpSubKey, DWORD Reserved, LPTSTR lpClass, DWORD dwOptions, REGSAM 
samDesired, PSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, 
LPDWORD lpdwDisposition) để tạo khóa mới. 
Bài giảng môn học: Lâp̣ triǹh Windows 
44 
2.3 Liêṭ kê các khóa 
 Hàm liệt kê các khóa trong CSDL Registry là hàm LONG RegEnumKeyEx(HKEY 
hKey, DWORD dwIndex, LPTSTR lpName, LPDWORD lpcbName, LPDWORD 
lpReserved, LPTSTR lpClass, LPDWORD lpcbClass, PFILETIME lpftLastWriteTime). 
3. Can thiêp̣ Windows qua Registry 
Hầu nhƣ tất cả các thay đổi, thiết lập của Windows đều có thể đƣợc thực hiện thông qua 
việc thiết lập các giá trị trong CSDL Registry, vấn đề cốt lõi là chúng ta cần nắm đƣợc khóa 
và giá trị cần thay đổi tƣơng ứng. 
3.1 Thay đổi giao diêṇ 
Để ngăn cấm không cho ngƣời dùng thay đổi Wallpaper chúng ta có thể thay đổi giá trị 
khóa:“HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/policies/ActiveDeskto
p” với giá trị DWORD là 1. 
Để chỉ định file Wallpaper của Windows ta có thể sửa các khóa 
“HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\ 
System” với các khóa là Wallpaper, WallpaperStyle và giá trị kiểu REG_SZ (String) là đƣờng 
dẫn tới file ảnh. 
3.2 Thay đổi các thiết lâp̣ đối với các ổ điã 
Để thay đổi thiết lập với các ổ đĩa ta thực hiện với các khóa 
HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices có tên là MountedDevices nhƣ hình 
sau: 
3.3 Thay đổi các thiết lâp̣ với ngƣời dùng 
Các biến môi trƣờng của một ngƣời dùng nằm trong phần 
“HKEY_CURRENT_USER\Environment”, còn cho cả hệ thống nằm trong phần 
“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session 
Manager\Environment”. 
Bài tập: 
Bài tập 1: Viết chƣơng trình thay đổi giao diện Windows bằng cách sử dụng can thiệp qua 
Registry. 
Bài tập 2: Viết chƣơng trình thay đổi các biến môi trƣờng của Windows bằng cách sử dụng 
can thiệp qua Registry. 
Bài giảng môn học: Lâp̣ triǹh Windows 
45 
Chƣơng 4: Quản lý các tiến triǹh và luồng 
1. Các tiến trình và luồng trên Windows 
Tất cả các tiến trình (process) của Windows đều có một hoặc nhiều luồng (thread) và 
luồng chính là đơn vị thực thi cơ sở nhất của Windows. Các luồng đƣợc lập lịch dựa trên các 
nhân tố: sự sẵn sàng của các tài nguyên nhƣ CPU và bộ nhớ vật lý, độ ƣu tiên. Windows hỗ 
trợ kiến trúc đa xử lý đối xứng SMP (Symmetric MultiProcessing) bắt đầu từ phiên bản NT4, 
do đó các luồng có thể chạy trên cac CPU riêng rẽ trong cùng một hệ thống. 
Trên quan điểm của lập trình viên mỗi tiến trình sẽ bao gồm các tài nguyên: 
+ Một hoặc nhiều luồng 
+ Một không gian bộ nhớ ảo riêng. 
+ Một hoặc nhiều đoạn mã, bao gồm của các đoạn mã trong các file DLL. 
+ Một hoặc nhiều phân đoạn dữ liệu chứa các dữ liệu toàn cục. 
+ Các giá trị biến môi trƣờng 
+ Vùng nhớ Heap 
+ Các tài nguyên khác chẳng hạn nhƣ các handle và các heap đã mở sẵn. 
Mỗi luồng trong một tiến trình sẽ chia sẻ mã chƣơng trình, các biến toàn cục, các biến 
môi trƣờng, các tài nguyên. Mỗi luồng sẽ đƣợc lập lịch một cách riêng rẽ và có các thành 
phần sau: 
+ Một ngăn xếp các lời gọi tới các thủ tục, các ngắt, các quản lý biệt lệ, và bộ nhớ 
+ Một mảng TLS (Threa Local Storage) các con trỏ để có thể cấp phát bộ nhớ lƣu trữ 
dữ liệu cho luồng. 
+ Một tham số trên stack, từ lúc bắt đầu tạo ra luồng, đƣợc sử dụng riêng cho mỗi 
luồng. 
+ Một cấu trúc ngữ cảnh, đƣợc quản lý bởi nhân. 
Bài giảng môn học: Lâp̣ triǹh Windows 
46 
2. Các thao tác với tiến trình 
2.1. Tạo tiến trình 
Hàm cơ bản để quản lý các tiến trình của Windows là hàm CreateProcess(), hàm này tạo 
ra một tiến trình với một luồng đơn. Tham số mà hàm cần là tên file chƣơng trình sẽ thực 
hiện. Chúng ta có thể thấy có nhiều đề cập tới khái niệm tiến trình cha, tiến trình con nhƣng 
thực sự thì quan hệ này không đƣợc quản lý bởi Windows. Windows đơn thuần chỉ tham 
chiếu tới các tiến trình tại ra một tiến trình con mà nó là tiến trình cha. 
Hàm CreateProcess() có 10 tham số: BOOL CreateProcess ( 
 LPCTSTR lpApplicationName, 
 LPTSTR lpCommandLine, 
 LPSECURITY_ATTRIBUTES lpsaProcess, 
 LPSECURITY_ATTRIBUTES lpsaThread, 
 BOOL bInheritHandles, 
 DWORD dwCreationFlags, 
 LPVOID lpEnvironment, 
Bài giảng môn học: Lâp̣ triǹh Windows 
47 
 LPCTSTR lpCurDir, 
 LPSTARTUPINFO lpStartupInfo, 
 LPPROCESS_INFORMATION lpProcInfo) 
2.2. Kết thúc và thoát khỏi môṭ tiến triǹh 
Sau khi tiến trình kết thúc, tiến trình, hay chính xác hơn là một luồng chạy trong tiến 
trình sẽ gọi tới hàm ExitProcess() để kết thúc tiến trình. Hàm này không trả về giá trị mà thay 
vào đó sẽ kết thúc tất cả các luồng của tiến trình. Hàm có thể gọi tới để lấy mã kết thúc một 
tiến trình là GetExitCodeProcess(). 
2.3. Các thao tác với biến môi trƣờng của Windows 
Để thao tác với các biến môi trƣờng của Windows ta dùng hai hàm sau: 
DWORD GetEnvironmentVariable ( 
 LPCTSTR lpName, 
 LPTSTR lpValue, 
 DWORD cchValue) 
BOOL SetEnvironmentVariable ( 
 LPCTSTR lpName, 
 LPCTSTR lpValue) 
2.4. Ví dụ: Ghi nhâṭ ký thời gian thƣc̣ hiêṇ của các tiến triǹh 
#include "EvryThng.h" 
int _tmain (int argc, LPTSTR argv []) 
{ 
 STARTUPINFO StartUp; 
 PROCESS_INFORMATION ProcInfo; 
 union { /* Structure required for file time arithmetic. */ 
 LONGLONG li; 
 FILETIME ft; 
 } CreateTime, ExitTime, ElapsedTime; 
 FILETIME KernelTime, UserTime; 
 SYSTEMTIME ElTiSys, KeTiSys, UsTiSys, StartTimeSys, ExitTimeSys; 
 LPTSTR targv = SkipArg (GetCommandLine ()); 
 OSVERSIONINFO OSVer; 
 BOOL IsNT; 
 HANDLE hProc; 
 OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 
Bài giảng môn học: Lâp̣ triǹh Windows 
48 
 GetVersionEx (&OSVer); 
 IsNT = (OSVer.dwPlatformId == VER_PLATFORM_WIN32_NT); 
 /* NT (all versions) returns VER_PLATFORM_WIN32_NT. */ 
 GetStartupInfo (&StartUp); 
 GetSystemTime (&StartTimeSys); 
 /* Execute the command line; wait for process to complete. */ 
 CreateProcess (NULL, targv, NULL, NULL, TRUE, 
 NORMAL_PRIORITY_CLASS, NULL, NULL, &StartUp, &ProcInfo); 
 /* Assure that we have all REQUIRED access to the process. */ 
 DuplicateHandle (GetCurrentProcess (), ProcInfo.hProcess, 
 GetCurrentProcess (), &hProc, 
 PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, 0); 
 WaitForSingleObject (hProc, INFINITE); 
 GetSystemTime (&ExitTimeSys); 
 if (IsNT) { /* W NT. Elapsed, Kernel, & User times. */ 
 GetProcessTimes (hProc, &CreateTime.ft, 
 &ExitTime.ft, &KernelTime, &UserTime); 
 ElapsedTime.li = ExitTime.li - CreateTime.li; 
 FileTimeToSystemTime (&ElapsedTime.ft, &ElTiSys); 
 FileTimeToSystemTime (&KernelTime, &KeTiSys); 
 FileTimeToSystemTime (&UserTime, &UsTiSys); 
 _tprintf (_T ("Real Time: %02d:%02d:%02d:%03d\n"), 
 ElTiSys.wHour, ElTiSys.wMinute, ElTiSys.wSecond, 
 ElTiSys.wMilliseconds); 
 _tprintf (_T ("User Time: %02d:%02d:%02d:%03d\n"), 
 UsTiSys.wHour, UsTiSys.wMinute, UsTiSys.wSecond, 
 UsTiSys.wMilliseconds); 
 _tprintf (_T ("Sys Time: %02d:%02d:%02d:%03d\n"), 
 KeTiSys.wHour, KeTiSys.wMinute, KeTiSys.wSecond, 
 KeTiSys.wMilliseconds); 
 } else { 
Bài giảng môn học: Lâp̣ triǹh Windows 
49 
 /* Windows 9x and CE. Elapsed time only. */ 
 ... 
 } 
 CloseHandle (ProcInfo.hThread); CloseHandle (ProcInfo.hProcess); 
 CloseHandle (hProc); 
 return 0; 
} 
3. Quản lý luồng (thread) trên Windows 
3.1. Các khái niệm cơ bản 
Trong phần trƣớc chúng ta đã xem xét cách thức một luồng thực hiện kết thúc một tiến 
trình. Các luồng trong một tiến trình chia sẻ chung dữ liệu và mã lệnh, vì thế về bản chất các 
luồng đó cũng có vùng nhớ riêng của chúng. Windows đáp ứng điều này bằng một số cách 
sau: 
+ Mỗi luồng có một stack của riêng nó cho các lời gọi hàm và các xử lý khác 
+ Lời gọi tiến trình có thể truyền một biến, con trò, tới thời gian tạo ra luồng. 
+ Mỗi luồng có thể cấp phát TLS của riêng nó. 
3.2. Mô hiǹh Boss/Worker và các mô hiǹh khác 
Lệnh grepMT minh họa cho mô hình Boss/Worker. Luồng boss (luồng chính) sẽ gán 
các tác vụ cho luồng worker để thực hiện. Mỗi luồng worker sẽ đƣợc cho một file để tìm kiếm 
và worker sẽ trả về giá trị của nó cho boss thread. Xem thêm ví dụ sắp xếp trộn để hiểu rõ mô 
hình này. 
3.3. Bô ̣nhớ dành cho luồng 
Các luồng có thể cần phải cấp phát và quản lý bộ nhớ của riêng nó và bảo vệ các vùng 
nhớ đó khỏi các luồng khác. Điều này đƣợc thực hiện qua các TLS, có thể minh họa bằng 
hình vẽ sau: 
Bài giảng môn học: Lâp̣ triǹh Windows 
50 
3.4. Độ ƣu tiên và các trạng thái của luồng 
Các luồng thuộc về nhân của Windows luôn có độ ƣu tiên cao nhất khi sẵn sàng để thực 
hiện. Một luồng đƣợc coi là không sẵn sàng để thực hiện nếu nó ở trạng thái chờ, treo, hay bị 
block bởi một lý do nào đó. 
4. Môṭ số ví du ̣về tiến triǹh và luồng 
4.1. Tìm kiếm song song với các tiến trình 
#include "EvryThng.h" 
int _tmain (DWORD argc, LPTSTR argv []) 
/* Create a separate process to search each file on the 
 command line. Each process is given a temporary file, 
 in the current directory, to receive the results. */ 
{ 
 HANDLE hTempFile; 
 SECURITY_ATTRIBUTES StdOutSA = /* SA for inheritable handle. */ 
 {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE}; 
 TCHAR CommandLine [MAX_PATH + 100]; 
 STARTUPINFO StartUpSearch, StartUp; 
 PROCESS_INFORMATION ProcessInfo; 
 DWORD iProc, ExCode; 
 HANDLE *hProc; /* Pointer to an array of proc handles. */ 
 typedef struct {TCHAR TempFile [MAX_PATH];} PROCFILE; 
 PROCFILE *ProcFile; /* Pointer to array of temp file names. */ 
 GetStartupInfo (&StartUpSearch); 
 GetStartupInfo (&StartUp); 
 ProcFile = malloc ((argc - 2) * sizeof (PROCFILE)); 
 hProc = malloc ((argc - 2) * sizeof (HANDLE)); 
 /* Create a separate "grep" process for each file. */  ... à không 
thƣc̣ hiêṇ lời goị với giá tri ̣ DLL _THREAD_ATTACH trƣớc đó nếu nhƣ thƣ viêṇ liên kết 
đôṇg đƣơc̣ gắn với môṭ tiến trình sau khi luồng đa ̃đƣơc̣ taọ ra. 
Luồng vâñ tồn taị khi hàm DllMain đƣơc̣ goị đến với tham số 
DLL_THREAD_DETACH. Nó thậm chí có thể gửi các thông điệp trong tiến trì nh. Nhƣng 
các luồng không nên sử dụng hàm PostMessage () vì luồng có thể kết thúc trƣớc khi thông 
điêp̣ đến đích. 
Chƣơng trình để test thƣ viêṇ liên kết đôṇg là môṭ chƣơng trình đơn giản và là môṭ 
Project khác (thuôc̣ loaị Win 32 Application). Chúng ta có thể để các file của 2 Project vào 
cùng một thƣ mục hoặc riêng rẽ trong 2 thƣ muc̣. 
Trong quá trình dic̣h chƣơng trình file simpledll .dll và simpledll .lib se ̃đƣơc̣ sinh ra 
trƣớc, file simpledll .lib se ̃đƣơc̣ tƣ ̣ đôṇg liên kết với chƣơng trình thƣ̉ nghiêṃ và file 
simpledll.dll se ̃đƣơc̣ nap̣ vào bô ̣nhớ khi chƣơng trình chaỵ . Cần chú ý là chƣơng trình 
usedll.exe không chƣ́a ma ̃của hàm sƣ̉ duṇg trong thƣ viêṇ , mã của hàm chỉ đƣợc nạp vào b ộ 
nhớ khi chƣơng trình chaỵ. 
Viêc̣ include file simpledll .h cũng giống nhƣ chúng ta include file windows .h, liên kết 
với file simpledll .lib cũng tƣơng tƣ ̣nhƣ liên kết với file user 32.lib và liên kết với file 
simpledll.dll cũng giống nhƣ chƣơng trình liên kết với file user32.dll. 
Măc̣ dù chúng ta xếp môṭ file DLL là môṭ mở rôṇg của Windows nhƣng nó cũng là môṭ 
mở rôṇg của chƣơng trình ƣ́ng duṇg của chúng ta . Tất cả nhƣ̃ng gì file DLL thƣc̣ hiêṇ đều là 
thay măṭ cho ƣ́ng duṇg sƣ̉ duṇg nó . Chẳng haṇ tất cả các thao tác cấp phát bô ̣nhớ đƣơc̣ kiểm 
soát bởi chƣơng trình . Bất cƣ́ cƣ̉a sổ nào nó taọ ra đều sở hƣ̃u bởi chƣơng trình và bất cƣ́ file 
nào đƣợc mở cũng đƣợc kiểm soát bởi ch ƣơng trình. Nhiều chƣơng trình có thể sƣ̉ duṇg cùng 
Bài giảng môn học: Lâp̣ triǹh Windows 
83 
môṭ file dll đồng thời , nhƣng Windows se ̃đóng vai trò lá chắn để ngăn chăṇ các can thiêp̣ lâñ 
nhau giƣ̃a các ƣ́ng duṇg này. 
Nhiều tiến trình có thể chia sẻ cùng môṭ môṭ đoaṇ ma ̃trong môṭ thƣ viêṇ liên kết đôṇg . 
Tuy nhiên dƣ́ liêụ đƣơc̣ sƣ̉ đuṇg bởi môṭ thƣ viêṇ DLL se ̃là khác nhau với các tiến trình khác 
nhau. Mỗi tiến trình có môṭ không gian điạ chỉ dƣ̃ liêụ của riêng nó để chƣ́a các dƣ̃ li ệu có thể 
sƣ̉ duṇg đến bởi file DLL . Chia sẻ bô ̣nhớ giƣ̃a các tiến trình đòi hỏi môṭ số kỹ thuâṭ khác mà 
chúng ta sẽ bàn tới trong phần tiếp theo. 
7.4. Chia sẻ bô ̣nhớ giƣ̃a các thƣ viêṇ liên kết đôṇg 
Windows cô lâp̣ các ƣ́ ng duṇg sƣ̉ duṇg cùng môṭ thƣ viêṇ liên kết đôṇg đồng thời . Tuy 
nhiên đôi khi đây không phải là môṭ lƣạ choṇ thích hơp̣ . Chúng ta có thể muốn viết một thƣ 
viêṇ DLL chƣ́a môṭ vùng nhớ nào đó có thể đƣơc̣ chia sẻ bởi nhiều ƣ́n g duṇg, hoăc̣ giƣ̃a các 
instance của cùng môṭ ƣ́ng duṇg. Điều này liên quan tới viê ̣sƣ̉ duṇg bô ̣nhớ chia sẻ , hay chính 
xác là một file ánh xạ bộ nhớ (memory-mapped file). 
Chúng ta sẽ khảo sát một chƣơng trình có tên là strprog (String Program ) và thƣ viện 
đƣơc̣ sƣ̉ duṇg là strlib (string library). Strlib chƣ́a 3 hàm mà strprog có thể gọi tới . Và một 
trong số các hàm của strlib se ̃sƣ̉ duṇg môṭ hàm call-back đƣơc̣ điṇh nghiã trong strprog. 
Strlib là môṭ thƣ viêṇ liên kết đôṇg chƣ́a và làm viêc̣ với môṭ xâu tối đa 256 ký tự. Xâu 
đƣơc̣ chuyển thành daṇg ký tƣ ̣hoa và kiểm soát trong vùng bô ̣nhớ chia sẻ của strlib . Strprog 
có thể sử dụng 3 hàm của thƣ viện Strlib để cộng , xóa và nhâṇ đƣơc̣ tất cả các xâu hiêṇ taị tƣ̀ 
strlib. Chƣơng trình strprog có hai muc̣ menu để lƣạ choṇ là Enter và Delete cho phép ngƣời 
dùng nhập các xâu để thực hiện việc cộng và xóa các xâu . Strprog se ̃in ra giá tri ̣ tất cả cá c 
xâu hiêṇ đang nằm chƣ́a trong thƣ viêṇ. 
Các hàm đƣợc định nghĩa trong thƣ viện Strlib gồm có: 
EXPORT BOOL CALLBACK AddString (pStringIn) 
EXPORT BOOL CALLBACK DeleteString (pStringIn) 
EXPORT int CALLBACK GetStrings (pfnGetStrCallBack, pParam) 
Hàm thứ nhất sẽ chuyển các xâu thành dạng ký tự hoa và thêm vào danh sách các xâu 
của thƣ viện. Giá trị trả về của hàm là TRUE (khác 0) nếu nhƣ thành công và FALSE (0) nếu 
nhƣ xảy ra lỗi : hoăc̣ xâu có đô ̣dài bằng 0 hoăc̣ không cấp phát đƣơc̣ bô ̣nhớ hoăc̣ đa ̃sƣ̉ duṇg 
hết 256 xâu của bô ̣nhớ. 
Hàm thứ hai sẽ thực hiện xóa bỏ một xâu khỏi danh sách các xâu của thƣ viện nếu khớp 
và nếu có nhiều xâu khớp thì chỉ xâu đầu tiên bị xóa . Kết quả trả về của hàm là TRUE nếu 
xóa bỏ thành công và FALSE nếu xâu cần xóa có độ dài bằng 0 hoăc̣ không tìm thấy. 
Hàm thứ ba là hàm sử dụng để liệt kê các xâu đang có trong thƣ viện , hàm này sử dụng 
môṭ tham số là môṭ hàm cal l-back chƣ́a trong chƣơng trình sƣ̉ duṇg hàm . Hàm này phải đƣợc 
điṇh nghiã trong chƣơng trình sƣ̉ duṇg thƣ viêṇ nhƣ sau: 
EXPORT BOOL CALLBACK GetStrCallBack (PSTR pString, PVOID pParam) 
Tham số pfnGetStrCallBack của hàm GetString chỉ tới m ột hàm call-back. GetString có 
thể goị tới hàm GetStrCallBack mỗi lần cho mỗi giá tri ̣ của môṭ xâu cho tới khi hàm này trả 
về FALSE. GetString se ̃trả về số lƣơṇg các xâu đƣơc̣ truyền cho hàm call -back. Biến pParam 
sẽ là một con trỏ far tới dƣ̃ liêụ đƣơc̣ ngƣời dùng điṇh nghiã. 
Bài giảng môn học: Lâp̣ triǹh Windows 
84 
Tất nhiên ở đây chúng ta cũng sƣ̉ duṇg hai phiên bản cho mỗi hàm , ANSI và Unicode 
version. 
7.5. Các vấn đề khác về thƣ viện liên kết động 
Tôi đa ̃tƣ̀ng đề câp̣ trong phần đầu củ a chƣơng này là các thƣ viêṇ liên kết đôṇg không 
nhâṇ các thông điêp̣ . Tuy nhiên môṭ thƣ viêṇ liên kết đôṇg có thể goị tới hàm GetMessage và 
PeekMessage. Các thông điệp mà thƣ viện lấy về từ hàng đợi thông điệp qua các hàm nà y 
thƣc̣ sƣ ̣là các thông điêp̣ của các chƣơng trình goị tới các hàm của thƣ viêṇ . Nói chung thƣ 
viêṇ làm viêc̣ thay măc̣ cho chƣơng trình goị nó – môṭ qui luâṭ chi phối hầu hết các hàm của 
Windows mà môṭ thƣ viêṇ có thể goị tới. 
Môṭ thƣ viêṇ liên kết đôṇg có thể nap̣ các tài nguyên (chẳng haṇ nhƣ các biểu tƣơṇg 
chƣơng trình, các xâu và các ảnh bitmap) tƣ̀ file thƣ viêṇ hoăc̣ tƣ̀ các file của chƣơng trình goị 
tới thƣ viêṇ đó. Các hàm nạp tài nguyên đòi hỏi môṭ handle tới instance . Nếu nhƣ thƣ viêṇ sƣ̉ 
dụng handle tới instance của riêng nó (đƣơc̣ truyền cho thƣ viêṇ qua viêc̣ goị tới hàm DllMain 
để khởi tạo nó ) thì thƣ viện có thể nhận đƣợc các tài nguyên từ file riêng c ủa nó. Để nap̣ các 
tài nguyên từ chƣơng trình gọi tới các hàm của thƣ viện , đòi hỏi handle tới instance của 
chƣơng trình goị hàm. 
Viêc̣ khai báo các lớp cƣ̉a sổ chƣơng trình và taọ ra cƣ̉a sổ chƣơng trình trong môṭ thƣ 
viêṇ đ òi hỏi một số thủ thuật . Cả cấu trúc lớp cửa sổ và hàm CreateWindow hoặc 
CreateWindowEx đều đòi hỏi môṭ handle tới môṭ instance của chƣơng trình . Măc̣ dù chúng ta 
có thể sử dụng hande của thƣ viện trong việc tạo ra các lớ p cƣ̉a sổ và cƣ̉a sổ chƣơng trình , các 
thông điêp̣ cƣ̉a sổ vâñ đi qua hàng đơị thông điêp̣ của chƣơng trình goị tới thƣ viêṇ khi thƣ 
viêṇ taọ ra cƣ̉a sổ chƣơng trình . Nếu nhƣ baṇ cần phải taọ ra các lớp cƣ̉a sổ và các cƣ̉a sổ 
chƣơng trình trong môṭ thƣ viêṇ thì tốt nhất là nên sƣ̉ duṇg handle tới instance của chƣơng 
trình gọi tới hàm thƣ viện. 
Vì các thông điệp cho các hộp thoại modal đƣợc nhận bên ngoài vòng lặp thông điệp 
của chƣơng trình nên chún g ta có thể taọ ra môṭ hôp̣ thoaị modal trong môṭ thƣ viêṇ bằng 
cách gọi tới hàm DialogBox . Handle tới instance có thể là của thƣ viêṇ hoăc̣ tham số 
hwndParent của hàm DialogBox có thể đăṭ bằng NULL . 
Các thƣ viện không có import 
Thay vì để Windows thƣc̣ hiêṇ viêc̣ liên kết đôṇg khi chƣơng trình lần đầu tiên đƣơc̣ 
nạp vào bộ nhớ chúng ta có thể liên kết một chƣơng trình với một thƣ viện khi chƣơng trình 
đang chaỵ. 
Chẳng haṇ chúng ta muốn goị tới hàm Rectangle nhƣ sau: 
Rectangle (hdc, xLeft, yTop, xRight, yBottom) ; 
Điều này se ̃làm cho chƣơng trình đƣơc̣ liên kết tới thƣ viêṇ gdi 32.lib khi biên dic̣h để 
lấy điạ chỉ của hàm Rectangle. Chúng ta có thể gọi tới hàm Rectangle theo một cách khác: 
typedef BOOL (WINAPI * PFNRECT) (HDC, int, int, int, int) ; 
khai báo hai biến: 
HANDLE hLibrary ; 
PFNRECT pfnRectangle ; 
Tiếp đến goị tới các hàm LoadLibrary và GetProcAddress : 
Bài giảng môn học: Lâp̣ triǹh Windows 
85 
hLibrary = LoadLibrary (TEXT ("GDI32.DLL")) 
pfnRectangle = (PFNPRECT) GetProcAddress (hLibrary, TEXT ("Rectangle")) 
Và bây giờ có thể gọi tới hàm Rectangle: 
pfnRectangle (hdc, xLeft, yTop, xRight, yBottom) ; 
FreeLibrary (hLibrary) ; 
Măc̣ dù kỹ thuâṭ sƣ̉ duṇg thƣ viêṇ liên kết đôṇg theo kiểu này kh ông làm tăng hiêụ quả 
sƣ̉ duṇg của hàm Rectangle nhƣng nó laị là môṭ cách hiêụ quả trong trƣờng hơp̣ mà chúng ta 
không biết tên của thƣ viêṇ cho tới khi chƣơng trình chaỵ (chẳng haṇ đối với hàm AlphaBlend 
chẳng haṇ). 
Đoaṇ ma ̃ trên sƣ̉ duṇg hai hàm LoadLibrary và FreeLibrary . Windows kiểm soát các 
biến đếm tham chiếu tới tất cả các module thƣ viêṇ . Hàm LoadLibrary sẽ làm cho biến đếm 
tham chiếu tới các thƣ viêṇ đƣơc̣ nap̣ tăng lên 1. Biến đếm tham chiếu cũng đƣợc tăng lên khi 
Windows nap̣ môṭ chƣơng trình có sƣ̉ duṇg thƣ viêṇ . FreeLibarary se ̃làm cho biến đếm này 
giảm đi 1, trƣờng hơp̣ môṭ instance của môṭ chƣơng trình sƣ̉ duṇg thƣ viêṇ bi ̣ loaị khỏi bô ̣nhớ 
biến đếm tham chiếu cũng giảm đi 1 đơn vi.̣ Khi biến đếm tham chiếu này bằng 0 Windows se ̃
loại bỏ thƣ viện khỏi bộ nhớ vì lúc đó thƣ viện không còn cần thiết nữa. 
Các thƣ viện chỉ chứa tài nguyên 
Bất cƣ́ hàm này trong môṭ thƣ viêṇ liên kết đô ̣ng mà môṭ chƣơng trình trên Windows và 
các thƣ viện khác có thể gọi tới đều phải đƣợc export . Tuy nhiên môṭ thƣ viêṇ liên kết đôṇg 
có thể không nhất thiết phải chứa bất cứ một hàm export nào . Vâỵ các thƣ viêṇ đó chƣ́a gì ? 
Câu trả lời là các tài nguyên. 
Chẳng haṇ chúng ta làm viêc̣ trên môṭ ƣ́ng duṇg Windows cần môṭ số các ảnh bitmap . 
Thông thƣờng chúng ta se ̃liêṭ kê các ảnh này trong file kic̣h bản tài nguyên và nap̣ chúng vào 
bô ̣nhớ với hàm LoadBitmap. Nhƣng có le ̃chúng ta muốn có môṭ số tâp̣ ảnh , mỗi tâp̣ cho môṭ 
đô ̣phân giải của màn hình hình thƣờng đƣơc̣ sƣ̉ duṇg với Windows . Giải pháp khả dĩ nhất là 
chƣ́a các tâp̣ ảnh khác nhau này vào các file khác nhau vì môṭ ngƣời dùng chỉ cần tới môṭ tâp̣ 
các ảnh này trên đĩa cứng. Và các file này đƣợc gọi là các file thƣ viện chỉ chứa tài nguyên . 
Hình 21-5 cho chúng ta thấy cách thƣ́c taọ ra môṭ thƣ viêṇ chỉ chƣ́a tài nguyên đƣơc̣ goị 
là bitlib.dll chƣ́a 9 ảnh bitmap. File bitlib.rc chƣ́a tất cả các ảnh này và gán cho mỗi ảnh môṭ 
số. Để taọ ra file bitlib .dll chúng ta cần có 9 ảnh có tên lần lƣợt là bitmap 1.bmp, 
bitmap2.bmp, , bitmap9.bmp. Chúng ta có thể sử d ụng các ảnh đi kèm với đĩa CD của 
quyển sách để dùng. 
Bài tập: 
Bài tập 1: Viết thƣ viện DLL chứa các hàm xử lý xâu. 
Bài giảng môn học: Lâp̣ triǹh Windows 
86 
Tài liệu tham khảo 
[1] Lê Hƣ̃u Đaṭ. Lâp̣ trình Windows. NXB Giáo duc̣. 
[2] Charles Petzold. Programming Windows, fifth edition. Microsoft Press. 1998. 
[3] Johnson M. Hart. Windows System Programming Third Edition. Addison Wesley 
Professional. 2004. 
Bài giảng môn học: Lâp̣ triǹh Windows 
87 
Đề thi tham khảo 
Đề số 1: 
Bài số 1 
Cho Dialog sau: 
Biết rằng các ID của các control của Dialog trên nhƣ sau : các ID của các Edit Text tƣơng ứng 
với các Static Text Canh a , Canh b , Canh c lần lƣơṭ là : ID_CANHA, ID_CANHB, 
ID_CANHC, ID của Static 1 là ID_KQKT, ID của Static 2 là ID_DTCV, ID của các Button 
Kiem tra và Thoat là ID _KIEMTRA, ID_THOAT. Hãy viết hàm xử lý cho Dialog trên sau 
cho khi nhấn vào nút Kiem tra thì chƣơng trình se ̃kiểm tra xem ba số nguyên đƣơc̣ nhâp̣ và 3 
Edit text tƣơng ƣ́ng có là 3 cạnh của 1 tam giác hay không , kết quả kiểm tra đƣơc̣ thông báo 
qua Static 1. Trong trƣờng hơp̣ là 3 cạnh của 1 tam giác haỹ tính và hiển thi ̣ chu vi , diêṇ tích 
của tam giác qua Static 2 và khi ngƣời dùng nhấn vào nút Thoat sẽ kết thúc Dialog. 
Bài số 2 
a) Hãy trình bày (đƣa ra ) dạng đơn giản nhất của một hàm xử lý thông điệp cửa sổ 
chƣơnh trình (hàm Window Proc). 
b) Giả sử chƣơng trình chỉ có một mục menu Help , trong đó có 2 mục menu con là 
Contents và About , hãy viết hàm xử lý thôn g điêp̣ cƣ̉a sổ chƣơng trình sao cho khi 
ngƣời dùng choṇ các muc̣ trong menu Help chƣơng trình se ̃hiển thi ̣ các thông báo 
(hàm Message Box) tƣơng ƣ́ng và khi ngƣời dùng nhấn chuôṭ trái vào 1 vị trí trên màn 
hình, hãy in ra một thông báo về toạ đô ̣chuôṭ taị vi ̣ trí đó (hàm TextOut). 
Đề số 2: 
Bài số 1 
Viết hàm xƣ̉ lý hôp̣ thoaị sau: 
Bài giảng môn học: Lâp̣ triǹh Windows 
88 
 Các điều khiển XA , YA, XB, YB, XC, YC là toạ đô ̣ 3 đỉnh trên măṭ phẳng toạ đô ̣
(nguyên). Khi nhấn nút “Tinh chu vi” haỹ tính chu vi của tam giác tạo thành bởi 3 đỉnh A, B, 
C và hiển thi ̣ lên IDC _KQ. Nhấn “Thoat” để thóat khỏi hôp̣ thoaị và nhấn “Tinh dien tich” se ̃
tính diện tích và hiển thị nhƣ trong phần tính chu vi 
Bài số 2 
a) Hãy trình bày (đƣa ra) dạng đơn giản nhất của một hàm xử lý thông điệp cửa sổ ch o 
môṭ hôp̣ thoaị. 
b) Hãy viết hàm WndProc cho một chƣơng trình có hệ thống menu gồm 1 mục File , 
trong đó có các muc̣ con với các chƣ́c năng sau : Menu1, Menu2, khi ngƣời dùng nhấn 
vào các mục này chỉ cần đƣa ra thông báo đơn giản , mục Exit để thoát khỏi chƣơng 
trình. 
Đề số 3: 
Bài số 1 
Viết hàm xƣ̉ lý hôp̣ thoaị sau: 
 Các điều khiển XA , YA, XB, YB, XC, YC là toạ đô ̣ 3 đỉnh trên măṭ phẳng tọa độ 
(nguyên). Khi nhấn nút “Tinh chu vi” haỹ tính chu vi của tam giác taọ thành bởi 3 đỉnh A, B, 
C và hiển thi ̣ lên IDC _KQ. Nhấn “Thoat” để thóat khỏi hôp̣ thoaị và nhấn “Tinh dien tich” se ̃
tính diện tích và hiển thị nhƣ trong phần tính chu vi 
Bài giảng môn học: Lâp̣ triǹh Windows 
89 
Bài số 2 
a) Hãy trình bày (đƣa ra) dạng đơn giản nhất của một hàm xử lý thông điệp cửa sổ ch o 
môṭ hôp̣ thoaị. 
b) Hãy viết hàm WndProc cho một chƣơng trình có hệ thống menu gồm 1 mục File , 
trong đó có các mu c̣ con với các chƣ́c năng sau : Menu1, Menu2, khi ngƣời dùng nhấn 
vào các mục này chỉ cần đƣa ra thông báo đơn giản , mục Exit để thoát khỏi chƣơng 
trình. 

File đính kèm:

  • pdfbai_giang_lap_trinh_windows_phan_2.pdf