Đồ án Quản lý phòng máy
Bạn đang xem 20 trang mẫu của tài liệu "Đồ án Quản lý phòng máy", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
Tài liệu đính kèm:
- do_an_quan_ly_phong_may.pdf
Nội dung text: Đồ án Quản lý phòng máy
- Chương 1 Tổng quan 1.1 Chương trình quản lý phòng máy bao gồm những gì? Trong quá trình khảo sát các chương trình quản lý phòng máy đang sử dụng tại Việt Nam, chúng em tạm phân loại các yêu cầu đề ra là : các yêu cầu cần, các yêu cầu đủ, và các yêu cầu mở rộng. 1.1.1 Các yêu cầu cần: Bản thân chương trình quản lý máy thuê Internet phải có khả năng tính tiền cước hợp lý cho người sử dụng. Người thuê máy cần cảm thấy việc tính cước đúng và làm họ hài lòng. Ngoài ra, nếu phòng máy còn có phục vụ món ăn, dịch vụ như: tạp chí, sách báo thì một yêu cầu cần khác là cần tính phí phục vụ cho người dùng. Đối với người dùng, họ cảm thấy hài lòng khi việc phục vụ được nhanh chóng và chu đáo. 1.1.2 Các yêu cầu đủ: Ngoài hai yêu cầu trên, việc bảo mật bảo mật và kiểm duyệt nội dung web cũng rất quan trọng do nó cũng ảnh hưởng một phần đến việc kinh doanh (chẳng hạn, thể gây ảnh hưởng uy tín phòng máy khi lướt web đen ). Vì vậy, các yêu cầu kiểm soát hệ thống máy khách được đặt ra như quan sát màn hình máy khách, đọc nội dung người dùng gõ 1.1.3 Các yêu cầu mở rộng: Ngoài các dạng yêu cầu trên, các yêu cầu còn lại là các yêu cầu mở rộng. Thật ra, các yêu cầu mở rộng chỉ có tính tương đối. Tùy thuộc yêu cầu đặt ra cho phần mềm mà ta có thể xem xét thêm các yêu cầu mở rộng như là yêu cầu đủ. Các yêu cầu mở rộng thường thấy là : lọc liên kết web, nội dung web, nhắn tin di động, chat nội bộ giữa các máy khách với nhau, đa ngôn ngữ 1
- 1.2 Các chương trình quản lý phòng máy hiện nay ở Việt Nam. 1.2.1 Cyber Station Manager Cyber Station Manager là phần mềm quản lý khách hàng, thời gian sử dụng máy trạm, điều khiển máy trạm do công ty trách nhiệm hữu hạn Đan Thanh viết. Chương trình có các chức năng chính: o Quản lý thông tin các máy trạm o Quản lý thông tin các hội viên o Quản lý hóa đơn 1.2.2 Internet Café Software: Do công ty PA Việt Nam 65 đường Sư Vạn Hạnh nối dài Q.10 Tp. Hồ Chí Minh viết. Các tính năng chính: o Quản lý thông tin các máy trạm 1.2.3 iSystem 3.0 : Hệ phần mềm chuyên nghiệp cho máy dịch vụ game – Internet, gồm hai phần : o iSystem hỗ trợ quản trị mạng từ bất cứ máy nào trong mạng nội bộ, hỗ trợ lọc web đen, biên tập danh bạ web, phân vùng khởi động, hỗ trợ kết nối Internet và ADSL. o iNetman hỗ trợ quản lý đồng thời nhiều loại dịch vụ (game, Internet ) và quản lý bán hàng. Do công ty TBNet 111 Lý Thường Kiệt Tp Thái Bình – tỉnh Thái Bình. 1.2.4 EasyCafe : Do công ty Tinasoft tại Thổ Nhĩ Kỳ viết. Các chức năng: o Quản lý thông tin các máy trạm. 2
- o Quản lý thông tin các hội viên. o Quản lý hóa đơn. o Lọc thông tin. o Nhắn tin di dộng. o Điều khiển từ xa các máy trạm. 1.3 Các ưu khuyết điểm của các chương trình trên. 1.3.1 Cyber Station Manager Ưu điểm : Phần mềm quản lý chi tiết việc phân loại khách hàng gồm : hội viên, khách vãng lai và người quản trị cả Server và Client. Các cách tính cước cho người dùng phong phú: trả tiền trước, trả tiền sau, cộng dồn tiền cước các máy(cho phép đổi máy sử dụng khi đang sử dụng máy nào đó). Cộng thêm thời gian sử dụng miễn phí cho khách. Thêm phí tự động cho khách khi khách có yêu cầu. Khuyết điểm: Cài đặt phức tạp( do dùng MySQL). Sử dụng Tiếng Việt không dấu. Các chức năng quản lý máy trạm đơn giản. Các chức năng điều khiển từ xa còn ít. 1.3.2 Internet Café Software Ưu điểm : - Giao diện đơn giản, dễ dùng. Có thể chuyển đổi máy cho khách hàng. - Màn hình screen che khá hiệu quả . Khuyết điểm: - Các chức năng không đầy đủ( Chương trình chỉ có phần tính cước, in báo biểu). 3
- - Phải đổi tên máy ngay khi bắt đầu sử dụng bên phía Server. Máy phải khởi động lại. 1.3.3 iSystem 3.0 Ưu điểm : - Giao diện đơn giản, dễ dùng. Có thể chuyển đổi máy cho khách hàng. Khuyết điểm: - Mặc dù có một số chức năng quản trị máy từ xa, nhưng vẫn còn rất ít (chỉ có tắt máy, nhắn tin từ máy chủ). - Phải đổi tên máy ngay khi bắt đầu sử dụng bên phía Server. Máy phải khởi động lại. 1.3.4 Easy Café: Ưu điểm : - Có gần như đầy đủ tất cả các chức năng quản lý cần thiết và mở rộng. - Hỗ trợ đa ngôn ngữ. - Có thể xem đây phần mềm điển hình về việc quản lý các máy trạm ở phòng cho thuê dịch vụ Internet. Khuyết điểm: - Vì phải quản lý chi tiết mọi thứ nên giao diện phức tạp, khó dùng. - Không hỗ trợ tiếng Việt mặc dù là phần mềm đa ngôn ngữ. 4
- Chương 2 Xây dựng chương trình quản lý phòng máy 2.1 Xác định yêu cầu: 2.1.1 Các yêu cầu chức năng: Xây dựng phần mềm quản lý phòng thuê Internet, chương trình có yêu cầu quản lý những tính năng cần là: Các tính năng cần là: Tính cước sử dụng máy Tính cước phục vụ món Quản lý báo cáo Các tính năng đủ là: Kiểm soát các họat động máy khách và nội dung sử dụng của người dùng 2.1.2 Các yêu cầu phi chức năng: 2.2 Phân tích thiết kế hệ thống: 2.2.1 Xây dựng Use Case: 2.2.1.1 Xác định Actor và Use Case phía Server: Actor: Người sử dụng chương trình Server ở máy chủ - Người quản lý. Use Case: Start Server: Chạy chương trình Server. Login: Cho phép Client sử dụng máy tính với trạng thái username=”anonymous” , password=””. Logout: Không cho phép Client sử dụng máy tính. Paid: Tính tiền người dùng. 5
- Banner: Thông tin (các nội quy của phòng máy ) người quản lý muốn cho khách hàng biết. Report : Report Debit: Thống kê các khách hàng nợ. Report Daily: Thống kê các thông tin kết nối của các máy khách hằng ngày. Report Month: Thống kê tình trạng sử dụng các máy theo tháng. Option : Manage Cafeteria: Người quản lý có thể xem, sửa hay bổ sung các loại món ăn, thức uống. Manage Kind of Food: Người quản lý có thể xem, sửa hay bổ sung các món ăn, thức uống. Manage Price Day: Người quản lý có thể xem, sửa hay bổ sung giá truy cập internet theo ngày cụ thể. Manage Debit: Người quản lý thêm vào cơ sở dữ liệu khách hàng còn nợ. Manage Member: Người quản lý có thể xem, sửa hay bổ sung thành viên. Administration: Lock Key: Cho phép người quản lý có thể khóa tất cả các phím hay một số phím trên một máy khách đang sử dụng. Log Key: Cho phép người quản lý có thể ghi nhận lại các phím khách hàng sử dụng trên một máy khách đang sử dụng. Manage Application: Cho phép người quản lý có thể biết được các ứng dụng chạy trên máy khách, và người quản lý cũng có thể bật hay tắt một ứng dụng nào đó. Manage Service: Cho phép người quản lý có thể biết được các service chạy trên máy khách, và người quản lý cũng có thể thay đổi loại 6
- khởi động (Automatic, Manual hay Disable) hay cũng có thể trạng thái service(Start hay Stop). Manage Remote Computer: Cho phép người quản lý có thể Logout, Restart hay Shutdown một máy khách bất kỳ hay cho tất cả các máy theo các tinh chỉnh về thời gian thực hiện. Send Message: Cho phép người quản lý có thể gởi tin nhắn đến một máy khách bất kỳ hay cho tất cả các máy. Snapshot: Cho phép người quản lý có thể chụp hình tĩnh hay hình động máy khách. Khi chụp tĩnh, tối đa chụp được 4 máy khách. Khi chụp động thì chụp được 1 máy khách. 2.2.1.2 Xác định các Actor và Use Case phía Client: Actor: Người sử dụng chương trình Screen. Use Case: Connect: thực hiện kết nối với Server để vào trạng thái chờ. Login Member: thực hiện login vào Server dưới hình thức Member. Actor: Người sử dụng chương trình Client. Use Case: Connect: thực hiện kết nối với Server để vào trạng thái sử dụng. Order: thực hiện đặt món ăn từ danh sách với Server. 2.2.1.3 Mô hình Use Case: 2.2.1.3.1 Phía Server 7
- Start Server Login (from Use Case) (from Use Case) Logout (from Use Case) Paid (from User Case) Administration User (from User) Set Banner (from Use Case) Change Option (from User) Report (from Use Case) Service order (from User) Hình 2-1 Mô hình Use Case tổng quát Month Report (from User) Daily Report (from User) Debit Report (from User) User Hình 2-2 Mô hình Use Case Report 8
- Manage Debit Manage Price Day Manage Kind of Food (from User) (from User) (from User) Manage Cafeteria Manage Member User (from User) (from User) Hình 2-3 Mô hình Use Case Manage Lock Key Log Key Manage Application (from User) (from User) (from User) Snap Shot Manage Service User (from User) (from User) Send Message Apply Policy Manage Remote Computer (from User) (from User) (from User) Hình 2-4 Mô hình Use Case Administrator 9
- 2.2.1.3.2 Phía Client: 2.2.1.3.2.1 Screen: Connect Login Member (from User) (from User) User Hình 2-5 Mô hình Use case Screen 2.2.1.3.2.2 Client: Connect Order (from User) User Hình 2-6 Mô hình Use case Client 10
- 2.2.2 Đặt tả Use Case: 2.2.2.1 Phía Server: 2.2.2.1.1 Start Server Use Case: Tên Use Case: Start Server. Mô tả : Server khởi động và lắng nghe kết nối. Dòng sự kiện : - Dòng sự kiện chính : + Người dùng khởi động chương trình. + Chương trình sẽ thực hiện việc mở cơ sở dữ liệu. + Kiểm tra thông tin kết nối . + Thực hiện việc lắng nghe các kết nối từ máy khách. - Dòng sự kiện khác: + Nếu có lỗi về việc mở cơ sở dữ liệu thì chương trình sẽ báo lỗi và thoát ra khỏi chương trình. + Nếu không có thông tin về số lượng máy có thể kết nối thì sẽ xuất thông báo yêu cầu nhập thông tin. + Nếu lần trước Server bị “chết”, thì bây giờ Server sẽ kiểm tra lại kết nối từ các máy khách. - Điều kiện tiên quyết: + Phải có cơ sở dữ liệu. - Điều kiện bổ sung : + Chương trình phải đăng ký các Active X về List View. - Điểm mở rộng: + Không có. 2.2.2.1.2 Login Use Case : Tên Use Case : Login. Mô tả : 11
- Người quản lý có thể cho máy khách login với tư cách là anonymous. Dòng sự kiện : -Dòng sự kiện chính : + Use case này bắt đầu khi người quản lý chọn Login. + Server kiểm tra xem máy khách có đang ở trạng thái chờ ? + Nếu hợp lệ Server gởi thông điệp đến máy khách. + Client nhận thông điệp sẽ tắt màn hình Screen và gởi thông điệp chấp nhận về Server. + Server nhận thông điệp sẽ cho phép khách hàng ở máy khách có thể sử dụng với tư cách anonymous. Chương trình bắt đầu tính tiền cho khách hàng từ lúc này cho đến lúc khách hàng kết thúc sử dụng - Dòng sự kiện khác : + Nếu Server kiểm tra máy khách không phải ở trạng thái chờ thì không cho Login. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Máy chuyển từ trạng thái chờ sang trạng thái sử dụng. - Điểm mở rộng: + Không có. 2.2.2.1.3 Logout Use Case: Tên Use Case : Logout. Mô tả : Kết thúc việc khách hàng sử dụng máy khách. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi khách hàng chọn Logout. + Server gởi thông điệp cho Client, cập nhật lại database. 12
- + Client nhận thông điệp và tắt hết các chương trình đang sử dụng. + Client bật màn hình che( màn hình Screen). + Màn hình che connect lại với Server. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Client phải Login vào Server trước. - Hậu điều kiện: + Máy chuyển từ trạng thái sử dụng sang trạng thái chờ. - Điểm mở rộng: + Không có . 2.2.2.1.4 Paid Use Case: Tên Use Case : Paid. Mô tả : Kết thúc việc khách hàng sử dụng máy khách và tính tiền. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý chọn Paid. + Server gởi thông điệp cho Client. + Client nhận thông điệp và tắt hết các chương trình đang sử dụng. + Client bật màn hình che( màn hình Screen). + Server tính tiền sử dụng và tiền các dịch vụ liên quan và xuất ra màn hình. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Client phải Login vào Server trước. - Hậu điều kiện: + Máy chuyển từ trạng thái sử dụng sang trạng thái chờ. 13
- - Điểm mở rộng: + Không có. 2.2.2.1.5 Service Order Use Case: Tên Use Case : Service Order. Mô tả : Phục vụ món ăn cho khách hàng. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi khách hàng yêu cầu phục vụ món ăn thức uống. + Người quản lý chọn máy khách mà khách hàng yêu cầu phục vụ. Khi đó danh sách các món ăn, thức uống mà khách hàng yêu cầu hiện ra. + Người quản lý phục vụ lần lượt các món ăn. Lúc đó, tiền dịch vụ được cập nhật vào trong tiền sử dụng máy. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Máy khách đang ở trạng thái sử dụng. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.6 Set Banner Use Case: Tên Use Case: Banner. Mô tả : Thông báo các quy định về sử dụng phòng máy cho khách hàng. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý chọn Set Banner. + Nhập các quy định mà người quản lý muốn khách hàng cần biết. 14
- + Server gởi thông điệp đến tất cả các máy khách có kết nối với Server. + Client nhận thông điệp sẽ cập nhật thông báo. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Máy khách đang ở trạng thái sử dụng. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.7 Daily Report Use Case: Tên Use Case: Daily Report. Mô tả: Hiển thị thông tin kết nối của các máy khách hằng ngày. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý chọn thống kê hàng ngày. + Chương trình đọc cơ sở dữ liệu từ bảng Daily Report và xuất ra màn hình. - Dòng sự kiện khác: + Nếu có lỗi cơ sở dữ liệu thì chương trình sẽ hiển thị thông báo. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.8 Month Report Use Case: 15
- Tên Use Case: Daily Report Mô tả: Hiển thị thông tin tiền của máy khách kiếm được trong cả tháng Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý chọn Month Report. + Chương trình đọc cơ sở dữ liệu từ bảng Month Report và xuất ra màn hình. - Dòng sự kiện khác: + Nếu có lỗi cơ sở dữ liệu thì chương trình sẽ hiển thị thông báo. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.9 Debit Report Use Case: Tên Use Case: Debit Report. Mô tả: Hiển thị danh sách các khách hàng còn nợ. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý chọn biểu tượng Debit Report. + Chương trình đọc cơ sở dữ liệu từ bảng Debit Report và xuất ra màn hình. + Khi người dùng chọn một khách hàng nợ thì thông tin chi tiết về người khách nợ đó sẽ xuất ra màn hình. - Dòng sự kiện khác: + Nếu có lỗi cơ sở dữ liệu thì chương trình sẽ hiển thị thông báo. 16
- - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.10 Manage Kind of Food Use Case: Tên Use Case: Kind of Food. Mô tả : Người quản lý có thể xem, sửa hay bổ sung các loại món ăn, thức uống. Dòng sự kiện : - Dòng sự kiện chính : + Use case này bắt đầu khi người quản lý chọn chức năng quản lý loại món ăn, thức uống. + Màn hình xuất danh sách các loại món ăn, thức uống. + Người quản lý có thể chọn chức năng edit để sửa đổi thông tin: luồng sự kiện phụ là sửa đổi một loại thức ăn được kích hoạt. + Người quản lý có thể chọn chức năng Add new để thêm thông tin luồng sự kiện phụ là thêm một loại thức ăn được kích hoạt. + Người quản lý có thể chọn chức năng Delete để xóa thông tin: luồng sự kiện phụ là xóa một loại thức ăn được kích hoạt. Sửa đổi một loại thức ăn: + Chọn loại thức ăn. + Nhập mới tên loại thức ăn. + Chọn chức năng Edit. 17
- + Chương trình sẽ cập nhật lại cơ sở dữ liệu. Thêm một loại thức ăn: + Nhập tên loại thức ăn. + Chọn chức năng Add. + Chương trình sẽ cập nhật lại cơ sở dữ liệu. Xóa một lọai thức ăn: + Chọn loại thức ăn. + Chọn chức năng Delete. + Chương trình sẽ cập nhật lại cơ sở dữ liệu. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.11 Manage Cafeteria Use Case: Tên Use Case: Manage Cafeteria. Mô tả: Người quản lý có thể xem, sửa hay bổ sung các món ăn. Dòng sự kiện : - Dòng sự kiện chính : + Use case này bắt đầu khi người quản lý chọn chức năng quản lý thức ăn, thức uống. + Màn hình xuất danh sách các món ăn, thức uống. + Người quản lý có thể chọn chức năng edit để sửa đổi thông tin: luồng sự kiện phụ là sửa đổi thức ăn, thức uống được kích hoạt. 18
- + Người quản lý có thể chọn chức năng Add new để thêm thông tin luồng sự kiện phụ là thêm thức ăn, thức uống được kích hoạt. + Người quản lý có thể chọn chức năng Delete để xóa thông tin:luồng sự kiện phụ là xóa thức ăn, thức uống được kích hoạt. Sửa đổi thức ăn, thức uống: + Chọn thức ăn, thức uống. + Nhập mới các thông tin cần thiết như tên , giá cả + Chọn chức năng Edit. + Chương trình sẽ cập nhật lại cơ sở dữ liệu. Thêm thức ăn, thức uống: + Nhập mới các thông tin cần thiết như tên , giá cả của thức ăn, thức uống. + Chọn chức năng Add. + Chương trình sẽ cập nhật lại cơ sở dữ liệu. Xóa thức ăn, thức uống: + Chọn thức ăn, thức uống. + Chọn chức năng Delete. + Chương trình sẽ cập nhật lại cơ sở dữ liệu. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 19
- 2.2.2.1.12 Manage Price Day Use Case: Tên Use Case: Manage Price Day. Mô tả: Người quản lý có thể xem, sửa hay bổ sung giá truy cập internet theo ngày cụ thể. Dòng sự kiện : - Dòng sự kiện chính : + Use case này bắt đầu khi người quản lý chọn chức năng quản lý giá dịch vụ. + Người quản lý chọn ngày cần quản lý. + Màn hình xuất giá truy cập 7 ngày trong tuần mà ngày đã chọn thuộc vào. + Người quản lý chọn các giờ rồi chọn chức năng edit để sửa đổi giá cả. - Dòng sự kiện khác: + Nếu không chọn thì giá cả là mặc định. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.13 Manage Debit Use Case: Tên Use Case: Manage Debit Mô tả : Người quản lý thêm vào cơ sở dữ liệu khách hàng còn nợ Dòng sự kiện : - Dòng sự kiện chính : + Use case này bắt đầu khi người quản lý chọn chức năng quản lý khách hàng nợ. 20
- + Màn hình sẽ hiển thị các thông tin cho người quản lý nhập mới. + Người quản lý chọn máy mà khách hàng đã sử dụng, khi đó danh sách các giờ Login vào máy đó sẽ xuất hiện. Người quản lý chọn một trong số các giờ bắt đầu đó. + Sau đó nhập vào một số thông tin (bao gồm Tên, Địa chỉ, Số điện thoại, tiền trả trước .). + Sau khi nhập xong, chương trình sẽ lưu xuống cơ sở dữ liệu - Dòng sự kiện khác: + Không có - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.14 Manage Member Use Case: Tên Use Case :Manage Member. Mô tả : Người quản lý Dòng sự kiện : - Dòng sự kiện chính : + Use case này bắt đầu khi người quản lý chọn chức năng quản lý thành viên của phòng máy. + Chương trình xuất hiện cửa sổ mới có danh sách các thành viên. 21
- + Người quản lý có thể chọn chức năng edit để sửa đổi thông tin: luồng sự kiện phụ là sửa đổi thành viên được kích hoạt. + Người quản lý có thể chọn chức năng Add new để thêm thông tin luồng sự kiện phụ là thêm thành viên được kích hoạt. + Người quản lý có thể chọn chức năng Delete để xóa 1 record luồng sự kiện phụ là xóa thành viên được kích hoạt. Sửa đổi thành viên: + Chọn thành viên. + Nhập mới các thông tin cần thiết như tên , địa chỉ, số điện thoại + Chọn chức năng Edit. + Chương trình cập nhật các thông tin thay đổi vào cơ sở dữ liệu. Thêm thức ăn, thức uống: + Nhập mới các thông tin cần thiết như tên , địa chỉ, số điện thoại của thành viên. + Chọn chức năng Add. + Chương trình lưu thông tin vào cơ sở dữ liệu. Xóa thức ăn, thức uống: + Chọn thành viên. + Chọn chức năng Delete. + Chương trình xóa thông tin trong cơ sở dữ liệu. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: 22
- + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.15 Lock Keys Use Case : Tên Use Case: Lock Keys. Mô tả : Cho phép người quản lý khóa các phím của máy khách. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý yêu cầu khóa phím. + Người quản lý chọn máy khách mà người quản lý muốn khóa. + Chọn chế độ khóa là khóa tất cả phím, khóa phím F1- >F2, khóa phím A->Z, khóa phím số , khóa phím dấu, khóa phím hỗ trợ, khóa phím bất kỳ. + Khi đó Server sẽ gởi thông điệp đến máy khách, máy khách nhận thông điệp sẽ thực hiện khóa phím tương ứng với chế độ khóa. + Nếu thực hiện thành công thì máy khách sẽ gởi thông điệp báo cho Server là khóa thành công. + Để kết thúc việc khóa, người quản lý chọn Mở khóa tất cả + Khi đó Server sẽ gởi thông điệp đến máy khách, máy khách nhận thông điệp sẽ thực hiện mở khóa tất cả các phím. + Nếu thực hiện thành công thì máy khách sẽ gởi thông điệp báo cho Server là mở khóa thành công. - Dòng sự kiện khác: + Nếu không thành công thì máy khách gởi thông điệp cho Server báo là không thành công. 23
- - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.16 Log Keys Use Case : Tên Use Case: Log Keys. Mô tả : Cho phép người quản lý có thể ghi nhận lại các phím khách hàng sử dụng trên máy khách. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý yêu cầu ghi nhận phím. + Người quản lý chọn máy khách mà người quản lý muốn ghi nhận phím. + Chọn bắt đầu ghi nhận. + Khi đó Server sẽ gởi thông điệp đến máy khách, máy khách nhận thông điệp sẽ ghi nhận các phím người dùng đã nhấn. + Người quản lý muốn xem những thông tin đã ghi nhận, sẽ dừng tiến trình ghi nhận thông tin. Khi đó Server sẽ gởi thông điệp đến máy khách, máy khách nhận thông điệp sẽ thực hiện gởi thông tin ghi nhận cho Server + Nếu nhận thông tin thành công Server sẽ thông báo thành công. + Người quản lý có thể xem thông tin ghi nhận. - Dòng sự kiện khác: 24
- + Không có. - Điều kiện tiên quyết: + Máy khách phải đang ở trạng thái sử dụng. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.17 Manage Application Use Case: Tên Use Case: Manage Application. Mô tả : Cho phép người quản lý có thể biết được các ứng dụng chạy trên máy khách, và người quản lý cũng có thể bật hay tắt một ứng dụng nào đó. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý yêu cầu quản lý ứng dụng trên máy khách. + Người quản lý chọn máy khách mà người quản lý muốn xem danh sách các ứng dụng. + Nếu người quản lý chọn xem danh sách các ứng dụng: Server gởi thông điệp yêu cẩu danh sách đến máy khách, máy khách thực hiện việc ghi lại danh sách các ứng dụng đang chạy ở máy khách và gởi về Server. + Nếu người quản lý chọn bật một ứng dụng: màn hình yêu cầu nhập các thông tin cần thiết (như tên ứng dụng, đường dẫn ) để bật ứng dụng, và Server gởi yêu cầu đến máy khách. Máy khách nhận thông điệp sẽ bật ứng dụng tương ứng. 25
- + Nếu người quản lý chọn tắt một ứng dụng: người quản lý chọn một ứng dụng từ danh sách, Server gởi yêu cầu đến máy khách. Máy khách nhận thông điệp sẽ tắt ứng dụng. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.18 Manage Service Use Case: Tên Use Case: Manage Service. Mô tả : Cho phép người quản lý có thể biết được các service chạy trên máy khách, và người quản lý cũng có thể thay đổi loại khởi động( Automatic, Manual hay Disable) hay cũng có thể thay đổi trạng thái service( Start hay Stop). Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý yêu cầu quản lý dịch vụ trên máy khách. + Người quản lý chọn máy khách mà người quản lý muốn xem thông tin service. + Nếu người quản lý chọn xem danh sách các dịch vụ: Server gởi thông điệp yêu cầu danh sách đến máy khách, máy khách thực hiện việc ghi lại danh sách các dịch vụ đang chạy ở máy khách và gởi về Server. 26
- + Nếu người quản lý chọn thay đổi loại khởi động dịch vụ: màn hình yêu cầu nhập loại tương ứng để thay đổi. Server gởi yêu cầu đến máy khách. Máy khách nhận thông điệp sẽ thay đổi tương ứng. + Nếu người quản lý chọn thay đổi trạng thái dịch vụ: màn hình yêu cầu chọn trạng thái tương ứng để thay đổi. Server gởi yêu cầu đến máy khách. Máy khách nhận thông điệp sẽ thay đổi tương ứng. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.19 Send Message Use Case: Tên Use Case: Send Message. Mô tả : Cho phép người quản lý có thể gởi tin nhắn đến một máy khách bất kỳ hay cho tất cả các máy Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý yêu cầu gởi tin nhắn. + Gởi đến một máy: người quản lý chọn máy khách mà người quản lý muốn gởi thông điệp. + Nhập thông điệp và yêu cầu Server gởi thông điệp đến máy đã chọn. 27
- + Gởi đến tất cả các máy: yêu cầu Server gởi thông điệp đến tất cả các máy. + Máy khách nhận thông điệp sẽ xuất ra màn hình. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.20 Manage Remote Computer: Tên Use Case: Manage Remote Computer. Mô tả : Cho phép người quản lý có thể Logout, Restart hay Shutdown một máy khách bất kỳ hay cho tất cả các máy. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người quản lý yêu cầu Logout, Restart hay Shutdown. + Nếu người quản lý yêu cầu Logout: luồng sự kiện phụ yêu cầu Logout được kích hoạt. + Nếu người quản lý yêu cầu Resstart: luồng sự kiện phụ yêu cầu Resstart được kích hoạt. + Nếu người quản lý yêu cầu Shutdown: luồng sự kiện phụ yêu cầu Shutdown được kích hoạt. Logout: + Người quản lý có thể chọn một máy hay tất cả máy. 28
- + Người quản lý có thể nhập thời gian. Sau thời gian đó chương trình sẽ thực hiện logout. + Người quản lý yêu cầu Logout. Server sẽ gởi thông điệp đến máy khách yêu cầu máy khách thực hiện logout. tương tự cho Restart và Shutdown - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: + Không có. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.1.21 SnapShot Use Case: Xem phần kỹ thuật. 2.2.2.2 Phía Client: 2.2.2.2.1 Screen 2.2.2.2.1.1 Screen Connect Use Case: Tên Use Case : Screen Connect. Mô tả : Máy khách thực hiện kết nối với Server để vào trạng thái chờ. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi máy khách bắt đầu chạy chương trình. 29
- + Chương trình kiểm tra thông tin kết nối và gởi thông điệp đến Server. + Nếu nhận được hồi đáp chấp nhận thì chương trình sẽ thực hiện kết nối với Server và màn hình chờ bật lên( Use Case thành công). - Dòng sự kiện khác: + Nếu các thông tin kết nối không có ( như thông tin về tên máy, địa chỉ IP SERVER, port ) thì sẽ nhập thông báo yêu cầu nhập thông tin lại. + Nếu tên máy trùng với một tên máy đã kết nối trước vào Server( do hồi đáp không chấp nhận của Server) thì cũng sẽ nhập thông báo yêu cầu nhập thông tin lại. + Nếu kết nối không thành công thì sẽ báo lỗi. - Điều kiện tiên quyết: + Server phải khởi động trước khi máy khách muốn kết nối vào màn hình chờ. - Hậu điều kiện: + Máy khách đang ở trạng thái down chuyển sang trạng thái chờ. - Điểm mở rộng: + Không có. 2.2.2.2.1.2 Login Member Use Case: Tên Use Case : Login Member. Mô tả: Máy khách thực hiện login vào Server dưới hình thức Member. Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi khách hàng bắt đầu đăng nhập vào Server để sử dụng máy. + Khách hàng nhập thông tin bao gồm Username và Password. 30
- + Chương trình gởi thông điệp đến Server. + Nếu nhận được hồi đáp chấp nhận thì màn hình chờ tắt, chương trình chính Client sẽ bật lên để tính giờ và khi đó khách hàng có thể sử dụng được máy này. - Dòng sự kiện khác: + Nếu nhận được hồi đáp từ chối thì màn hình screen vẫn không bị tắt. - Điều kiện tiên quyết: + Server phải khởi động trước. + Máy khách đang ở trạng thái chờ. - Hậu điều kiện: + Máy khách đang ở trạng thái chờ chuyển sang trạng thái sử dụng. - Điểm mở rộng: + Không có. 2.2.2.2.2 Client 2.2.2.2.2.1 Client Connect Use Case: Tên Use Case : Client Connect. Mô tả: Máy khách thực hiện kết nối với Server để vào trạng thái sử dụng Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi người dùng login thành công vào Server. + Chương trình kết nối với Server. + Server nhận được thông điệp kết nối sẽ bắt đầu gởi danh sách các món ăn, banner cho Client. + Máy khách sẽ nhận thông điệp từ Server sẽ lưu trữ các thông tin đó. 31
- + Máy khách xuất thông báo về nội quy sử dụng phòng máy. - Dòng sự kiện khác: + Nếu kết nối không thành công thì sau 1 khoảng thời gian máy khách sẽ tự động thực hiện kết nối lại với Server. - Điều kiện tiên quyết: + Server phải khởi động trước khi máy khách muốn kết nối vào màn hình chờ. + Máy khách đang ở trạng thái chờ. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.2.2.2.2 Order Use Case: Tên Use Case : Order Mô tả : Khách hàng có thể thực hiện đặt món ăn từ danh sách với Server Dòng sự kiện : - Dòng sự kiện chính : + Use case bắt đầu khi khách hàng yêu cầu phục vụ. + Danh sách các thức ăn, thức uống sẽ xuất hiện. + Khách hàng chọn các thông tin cần thiết như món ăn, số lượng + Khi khách hàng yêu cầu phục vụ các món mình đã chọn thì máy khách sẽ gởi thông điệp cho Server. + Server nhận thông điệp sẽ lần lượt phục vụ các món ăn khách hàng đã yêu cầu. - Dòng sự kiện khác: + Không có. - Điều kiện tiên quyết: 32
- + Server phải khởi động trước khi máy khách muốn kết nối vào màn hình chờ. + Phía máy khách đang ở trong trạng thái sử dụng. - Hậu điều kiện: + Không có. - Điểm mở rộng: + Không có. 2.2.3 Thiết kế lớp trên Server: 2.2.3.1 Giao diện Server: 33
- CChgSrvStartupDlg CDebitDetailReportDlg CDebitReportDlg CMonthReport CChgSrvStatusDlg CDailyReportDlg CSrvListTab CInputPriceDlg CApplistTab Hình 2-7 Thi Hình CAdminTab CDebitDlg CScrCapTab CInputMemberDlg ế t k CCafeServerDlg CMessageTab ế l 34 ớ CInputDishDlg p giao di p giao CKeyLogTab CParentTabPage CInputValueDlg ệ CLockKeyAddDlg CKeyLockTab n Server n Server CInputCategoryDlg CLoggingTab CInfoServerDlg CTabCtrlSSL CBannerDlg CEnTabCtrl CBaseTabCtrl CTabPageSSL CServiceTab CWorkStationTab CAfterCrashDlg
- STT Tên lớp Kế thừa từ lớp Chức năng dùng tự vẽ giao diện 1 CBaseTabCtrl CTabCtrl tab ctrl dùng tô màu đỉnh Tab 2 CEnTabCtrl CBaseTabCtrl theo màu nền dùng Add Dialog (xem 1 dialog như một trang 3 CTabCtrlSSL CEnTabCtrl của tab) dùng để thể hiện dialog như một trang 4 CTabPageSSL CDialog của Tab dùng để tô màu nền 5 CParentTabPage CTabPageSSL và gắn tooltip giao diện để điều khiển hoạt động máy 6 CLoggingTab CParentTabPage tính giao diện để khóa bàn 7 CKeyLockTab CParentTabPage phím giao diện dùng để ghi 8 CKeyLogTab CParentTabPage phím giao diện dùng để cho người dùng nhập các 9 CLockKeyAddDlg CParentTabPage phím cần khóa giao diện dùng để người quản lý gởi tin 10 CMessageTab CParentTabPage nhắn đến một máy 35
- hay nhiều máy giao diện dùng để 11 CScrCapTab CParentTabPage chụp màn hình giao diện dùng để quản lý các ứng dụng 12 CApplistTab CParentTabPage phía máy khách giao diện dùng để quản lý phục vụ các dịch vụ như món ăn, thức uống cho khách 13 CServiceTab CParentTabPage hàng nhập dữ liệu về trạng thái hoạt động của 14 CChgSrvStartupDlg CDialog dịch vụ nhập dữ liệu về trạng thái khởi động của 15 CChgSrvStatusDlg CDialog dịch vụ giao diện dùng để quản lý các service 16 CSrvListTab CParentTabPage phía máy khách dùng để chứa các 17 CAdminTab CParentTabPage giao diện quản trị dùng để quản lý việc tính cước, giá cả các 18 CWorkStationTab CParentTabPage dịch vụ kèm theo dùng quản lý chương trình sau khi có một 19 CAfterCrashDlg CDialog client bị đứt kế nối 20 CBannerDlg CDialog giao diện dùng nhập 36
- banner, rồi xuất các quy định ở máy khách giao diện dùng nhập các thông tin về 21 CInfoServerDlg CDialog Server lúc bắt đầu giao diện dùng quản lý loại thức ăn, nước 22 CInputCategoryDlg CDialog uống giao diện dùng quản lý các món ăn, thức 23 CInputDishDlg CDialog uống giao diện dùng quản lý 24 CInputMemberDlg CDialog thanh viên tham gia giao diện dùng quản lý 25 CDebitDlg CDialog các khách hàng nợ giao diện dùng quản lý 26 CInputPriceDlg CDialog giá cả các ngày giao diện dùng nhập 27 CInputValueDlg CDialog giá cả của ngày giao diện dùng thống kê các đăng nhập sử 28 CDailyReportDlg CDialog dụng của khách hàng giao diện dùng thống kê số tiền máy khách kiếm được trong một 29 CMonthReport CDialog tháng giao diện dùng thống 30 CDebitReportDlg CDialog kê các khách hàng nợ 31 CdebitDetail- CDialog giao diện dùng xuất 37
- ReportDlg chi tiết về một khách hàng nợ giao diện chương 32 CCafeServerDlg CDialog trình Server 2.2.3.2 Xử lý Server: CSolveMember CInputPriceDay CSolveCategory CInputDish CSolveDish CInputCategory CSolveDailyReport CSolveLogin CCafeDB CSolveFee CSolveMonthReport CSolveTableFee CSolveDebitList CSolveFeeDay CSolveDebitDetail CADODatabase CADORecordSet CADOCommand CADOFieldInfo CADOParameter CADOException Hình 2-8 Thiết kế lớp xử lý Server 38
- STT Tên lớp Kế thừa từ lớp Chức năng Lớp xử lý việc quản 1 CSolveMember CCafeDB lý các thành viên Lớp xử lý việc quản lý các loại món ăn, 2 CSolveCategory CCafeDB thức uống Lớp xử lý việc quản lý các món ăn, thức 3 CSolveDish CCafeDB uống Lớp xử lý việc quản 4 CSolveLogin CCafeDB lý Login,Logout Lớp xử lý việc tính 5 CSolveFee CCafeDB tiền Lớp xử lý việc quản 6 CSolveTableFee CCafeDB lý tiền phí Lớp xử lý việc quản 7 CSolveFeeDay CCafeDB lý tiền phí Lớp xử lý việc quản 8 CInputPriceDay CCafeDB lý giá cả Lớp xử lý việc quản 9 CInputDish CCafeDB lý món ăn,thức uống Lớp xử lý việc quản 10 CInputCategory CCafeDB lý loại món ăn Lớp xử lý việc báo 11 CSolveDailyReport CCafeDB cáo hàng ngày Lớp xử lý việc báo 12 CSolveMonthReport CCafeDB cáo theo tháng 13 CSolveDebitList CCafeDB Lớp xử lý việc nợ 39
- của các thành viên Lớp xử lý việc nợ của các thành viên 14 CSolveDebitDetail CCafeDB một cách chi tiết 15 CADODatabase CADOCommand 16 CADORecordset CADOCommand, CADOFieldInfo 17 CADOCommand CADOParameter 18 CADOFieldInfo 19 CADOParameter 20 CADOException 2.2.4 Thiết kế lớp trên Client: 2.2.4.1 Screen: CSockAddr CBlockingSocket CBlockingSocketException CInfoPcDlg CScreenDlg CLogonDlg Hình 2-9 Thiết kế lớp Screen Kế thừa từ STT Tên lớp lớp Chức năng Chỉ địa chỉ IP, thông tin Port 1 CSockAddr sockaddr_in dịch vụ 40
- Nó thay thế lớp Socket của MFC. Đây là lớp giữ chức năng quan trọng nhất trong chương trình vì nó có thể thiết lập, tiếp nhận kết nối và 2 CBlockingSocket CObject quản lý việc truyền dữ liệu. Lớp quản lý lỗi cho việc thiết CblockingSocket- lập, tiếp nhận kết nối và quản 3 Exception CException lý việc truyền dữ liệu. Dùng để nhập thông tin khi 4 CInfoPcDlg không có thông tin kết nối Dùng để nhập thông tin 5 CLogonDlg Logon Giao diện che màn hình không cho khách hàng sử 6 CScreenDlg dụng máy khách 2.2.4.2 Client: CCafeClientDlg COrder CKeyLogClient CTaskMgr CShutdownClient CKeyLockCLient CKeyClient CSockAddr CBlockingSoket CBlockingSocketException Hình 2-10 Thiết kế lớp Client 41
- Kế thừa từ STT Tên lớp lớp Chức năng Chỉ địa chỉ IP, thông tin 1 CSockAddr sockaddr_in Port dịch vụ Nó thay thế lớp Socket của MFC. Đây là lớp giữ chức năng quan trọng nhất trong chương trình vì nó có thể thiết lập, tiếp nhận kết nối và quản lý 2 CBlockingSocket CObject việc truyền dữ liệu. Lớp quản lý lỗi cho việc thiết lập, tiếp nhận kết nối CblockingSocket- và quản lý việc truyền dữ 3 Exception CException liệu. Lớp quản lý lỗi cho việc 4 CKeyClient Lock hay Log key Giao diện phục vụ việc đặt món ăn của khách 5 COrder CDialog hàng 6 CKeyLockClient CKeyClient Lớp xử lý khóa phím Lớp xử lý ghi nhận phím 7 CKeyLogClient CKeyClient sử dụng Giao diện chính của 8 CCafeClientDlg chương trình Client 42
- 2.2.5 Hiện thực hóa Use Case: 2.2.5.1 Use case Start Server: : User Object1 : CCafeServerDlg Object2 : CBlockingSocket 1: StartServer( ) 2: CreateConnection( ) 3: StartListenConnection( ) Hình 2-11 Sequence Diagram Start Server 43
- 2.2.5.2 : User Object1 : CWorkStationTab Object2 : CSolveLogin Object3(Server) : CObject4(Screen) : Object5 : CScreenDlg Object6(Client) : Object7 : CCafeClientDlg CBlockingSocket CBlockingSocket CBlockingSocket 1: LoginComputer( ) 2: CheckDatabase( ) Use case Login: Use caseLogin: Hình 2-12 Sequence Diagram Login Sequence DiagramLogin 2-12 Hình 3: SetInfo( ) 4: SendMessage( ) 5: CloseApplication( ) 6: SendMessage( ) 44 7: Close( ) Close Successful 8: Connect( ) 9: SendMessage( ) 10: AcceptConnection( )
- 2.2.5.3 : User Object1 : CWorkStationTab Object2 : CSolveLogin Object3 : Object4(Server) : Object5(Screen) : Object6 : CScreenDlg Object7(Client) : Object8 : CCafeClientDlg CSolveDailyReport CBlockingSocket CBlockingSocket CBlockingSocket 1: LogoutComputer( ) 2: DeleteInfoLogin( ) Use case Logout: Use caseLogout: 3: SaveClientInfo( ) Hình 2-13 Sequence Diagram Logout Hình 2-13Sequence 4: Delete Client Info 5: LogoutComputer( ) 6: SendMessage( ) 7: CloseConnection( ) 8: CloseConnection( ) 45 9: StartScreen( ) 10: StartConnection( ) 11: SendMessage( ) 12: AcceptConnection( )
- 2.2.5.4 Object4 : CSolveFee : User Object1 : CWorkStationTab Object2 : CSolveLogin Object3 : Object7(Server) : Object5 : CSolveFeeDay Object6 : CSolveDailyReport CBlockingSocket Use casePaid CSolveTableFee 1: PaidComputer( ) Hình 2-14 Sequence Diagram Paid Diagram Hình 2-14Sequence 2: ComputerFee( ) 3: ComputerFee( ) 4: SetDay( ) 5: GetTable( ) 46 6: GetPrice( ) 7: ComputeFee( ) 8: GetFee( ) 9: SaveClientInfo( ) 10: Fee( ) 11: DeleteClientInfo( ) 12: LogoutComputer( )
- 2.2.5.5 Use Case SetBanner: : User Object1 : CCafeServerDlg Object2(Server) : Object3(Client) : Object2 : CCafeClientDlg CBlockingSocket CBlockingSocket 1: EnterBanner( ) 2: SetBanner( ) 3: SendMessage( ) 4: GetBanner( ) 5: ShowBanner( ) Hình 2-15 Sequence Diagram SetBanner 2.2.5.6 Use Case Service Order : User Object1 : CServiceTab Object2 : CMyHFlexGrid Object2 : CWorkStationTab Object3 : CSolveLoginService 1: ServeDish( ) 2: ShowInfo( ) 3: UpdateServiceFee( ) 4: SaveToDatabase( ) Hình 2-16 Sequence Diagram Service Order 2.2.5.7 Use case Daily Report 47
- : User Object1 : CDailyReportDlg Object2 : CDailyReportFlexGrid Object3 : 1: DailyReport( ) CSolveDailyReport 2: OpenDatabase( ) 3: GetAllInfo( ) 4: ShowReport( ) Hình 2-17 Sequence Diagram Daily Report 48
- 2.2.5.8 Object5 : Object6 : : User Object1 : CDebitReportDlg Object2 : CDebitReportFlexGrid Object3 : Object4 : CDebitDetailReportDlg CDebitDetailReportFlexGrid CSolveDebitDetailReport CSolveDebitList 1: DebitReport( ) Hình 2-18 Sequence Di 2-18 Sequence Hình Use case Debit Report: Use caseDebitReport: 2: OpenDatabase( ) 3: GetAllInfo( ) 4: ShowReport( ) 5: ReportDetail( ) 49 agram Debit Report Debit agram 6: SetReportInfo( ) 7: Opendatabase( ) 8: GetAllInfo( ) 9: ShowDetail( )
- 2.2.5.9 Use case Month Report : User Object1 : CMonthReportDlg Object2 : CMSFlexGrid Object3 : 1: MonthReport( ) CSolveMonthReport 2: OpenDatabase( ) 3: GetAllInfo( ) 4: ShowReport( ) Hình 2-19 Sequence Diagram Month Report 2.2.5.10 Use case Manage Cafeteria: 2.2.5.10.1 Show: : User Object1 : CInputCategoryDlg Object2 : CCategoryListFlexGrid Object3 : CInputCategory 1: Category( ) 2: OpenDatabase( ) 3: GetAllInfo( ) 4: ShowCategory( ) Hình 2-20 Sequence Diagram Manage Cafeteria Show 50
- 2.2.5.10.2 Add: : User Object1 : CInputCategoryDlg Object3 : CInputCategory Add new Category 1: EnterNewInfo( ) 2: Add( ) 3: SetInfo( ) 4: Save( ) Hình 2-21 Sequence Diagram Manage Cafeteria Add 2.2.5.10.3 Edit : User Object1 : CInputCategoryDlg Object2 : CCategoryListFlexGrid Object3 : CInputCategory 1: ChooseCategory( ) 2: Edit( ) 3: UpdateInfo( ) 4: Update( ) Hình 2-22 Sequence Diagram Manage Cafeteria Edit 51
- 2.2.5.10.4 Delete: Object3 : CInputCategory : User Object1 : CInputCategoryDlg Object2 : CCategoryListFlexGrid 1: ChooseCategory( ) 2: Delete( ) 3: DeleteCategory( ) 4: Delete( ) Hình 2-23 Sequence Diagram Manage Cafeteria Delete 2.2.5.11 Use case Manage Debit 2.2.5.11.1 Add 52
- : User Object1 : CCafeServerDlg Object2 : CDebitDlg Object3 : Object4 : Object5 : CSolveDailyReport CSolveDebitList CSolveDebitDetail 1: Debit( ) Hình 2-24 Sequence Hình 2-24Sequence 2: OpenForm( ) Add new Debit Person 3: EnterInfo( ) 4: GetAllPersonInfo( ) 53 5: SetBasicInfo( ) Diagram DebitAdd Diagram 6: Save( ) 7: GetDetailInfo( ) 8: SetDetailInfo( ) 9: save( )
- : User Object1 : CCafeServerDlg Object2 : CDebitDlg Object3 : Object4 : CSolveDebitList Object5 : CSolveDailyReport CSolveDebitDetail 1: Debit( ) Hình 2-25 2: EnterBasicInfo( ) 3: SetBasicInfo( ) 4: GetBasicInfo( ) Sequence Diagram Manage Debit Edit Debit Manage Diagram Sequence 5: SetDetailInfo( ) 6: GetDetailInfo( ) 7: ShowInfo( ) 54 8: Edit( ) 9: SetBasicInfo( ) 10: Save( ) 11: SetDetailInfo( ) 12: save( )
- 2.2.5.12 Use case Manage Kind of Food: 2.2.5.12.1 Add : User Object1 : CInputDishDlg Object2 : CDishListFlexGrid Object3 : CInputDish 1: Dish( ) 2: OpenDatabase( ) 3: GetAllInfo( ) 4: ShowDish( ) Add new Dish 5: EnterNewInfo( ) 6: Add( ) 7: SetInfo( ) 8: Save( ) Hình 2-26 Sequence Diagram Manage Kind of Food Add 2.2.5.12.2 Edit 55
- : User Object1 : CInputDishDlg Object2 : CDishListFlexGrid Object3 : CInputDish 1: Dish( ) 2: OpenDatabase( ) 3: GetAllInfo( ) 4: ShowDish( ) 5: ChooseDish( ) 6: Edit( ) 7: UpdateInfo( ) 8: Update( ) Hình 2-27 Sequence Diagram Manage Kind of Food Edit 2.2.5.12.3 Delete 56
- : User Object1 : CInputDishDlg Object2 : CDishListFlexGrid Object3 : CInputDish 1: Dish( ) 2: OpenDatabase( ) 3: GetAllInfo( ) 4: ShowDish( ) 5: ChooseDish( ) 6: Delete( ) 7: DeleteDish( ) 8: Delete( ) Hình 2-28 Sequence Diagram Manage Kind of Food Delete 2.2.5.13 Use case Manage Member: 2.2.5.13.1 Add 57
- : User Object1 : CInputMemberDlg Object2 : CMemberFlexGridObject3 : CSolveMember 1: Member( ) 2: OpenDatabase( ) 3: GetInfo( ) 4: ShowMember( ) Add Member 5: EnterInformation( ) 6: Add( ) 7: SetInfo( ) 8: Save( ) Hình 2-29 Sequence Diagram Manage Member Add 2.2.5.13.2 Edit 58
- : User Object1 : CInputMemberDlg Object2 : CMemberFlexGridObject3 : CSolveMember 1: Member( ) 2: OpenDatabase( ) 3: GetInfo( ) 4: ShowMember( ) Edit Member 5: ChooseMember( ) 6: Edit( ) 7: SetInfo( ) 8: Update( ) Hình 2-30 Sequence Diagram Manage Member Edit 2.2.5.13.3 Delete 59
- : User Object1 : CInputMemberDlg Object2 : CMemberFlexGridObject3 : CSolveMember 1: Member( ) 2: OpenDatabase( ) 3: GetInfo( ) 4: ShowMember( ) Delete Member 5: ChooseMember( ) 6: Delete( ) 7: SetInfo( ) 8: Update( ) Hình 2-31 Sequence Diagram Manage Member Delete 60
- 2.2.5.14 : User Object1 : CInputPriceDayDlg Object2 : CPriceDayListFlexGrid Object3 : CInputValuePriceDay Object4 : Object5 : 1: PriceDay( ) CInputPriceDay CSolveFeeTable Object6 : CSolveFeeDay 2: OpenDatabase( ) Hình 2-32 Sequence Diag Hình 2-32Sequence 3: SetDay( ) Use caseManagePriceDay: 4: GetInfoTable( ) 5: SetInfoTable( ) 6: GetFeeDayFromInfoTable( ) 7: GetAllInfo( ) 8: ShowPriceDay( ) Edit Price Of Day 61 9: ChooseDay&Time( ) ram Manage PriceDay 10: Edit( ) 11: EnterNewInfo( ) 12: OpenForm( ) 13: EnterValue( ) 14: GetValue( ) 15: ShowNewPrice( ) 16: SetInfoTable( ) 17: SetFeeDay( )
- 2.2.5.15 : User Object1 : CCafeServerDlg Object2(Server) : Object3(Client) : Object4 : CCafeClientDlg Object5 : CKeyLockClient CBlockingSocket CBlockingSocket 1: ChoosetheModeLock( ) Use case Lock Key: Use caseLock Key: Hình 2-33 Sequence Diagram Lock Key Key Diagram Lock Hình 2-33Sequence 2: StartKeyLock( ) 3: SetInfo( ) 4: SendMessage( ) 5: GetInfo( ) 6: LockKey( ) 62 Lock Successful 7: SetInfo( ) 8: SendMessage( ) 9: ShowMessage( )
- 2.2.5.16 : User Object1 : CCafeServerDlg Object2(Server) : Object3(Client) : Object4 : CCafeClientDlg Object5 : CKeyLogClient CBlockingSocket CBlockingSocket 1: StartKeyLog( ) Use case Log Use caseLog Key Hình 2-34 Sequence Hình 2-34Sequence 2: SetInfo( ) 3: SendMessage( ) 4: GetInfo( ) 5: LogKey( ) 63 Log Successful Diagram Log Key LogKey Diagram 6: SetInfo( ) 7: SendMessage( ) 8: ShowMessage( )
- 2.2.5.17 Use case Message: : User Object : CMessageTab Object : CBlockingSocket Object : CBlockingSocket Object : CCafeClientDlg 1: ChooseComputer( ) 2: EnterMesage( ) 3: SetInfo( ) 4: SendMessage( ) 5: GetInfo( ) 6: ShowMessage( ) Hình 2-35 Sequence Diagram Send Message 2.2.5.18 Use case Manage Remote Computer : User Object : CLoggingtab Object(Server) : Object(Client) : Object : CCafeClientDlg Object : CShutDownClient CBlockingSocket CBlockingSocket 1: SetOption 2: Shutdown 3: SetInfo( ) 4: SendMessage( ) 5: GetInfo( ) 6: Shutdown( ) 7: Shutdown( ) Hình 2-36 Sequence Diagram Manage Remote Computer 64
- 2.2.5.19 Use case Manage Application: 2.2.5.19.1 List: : User Object1 : CAppListtab Object2(Server) : Object3(Client) : Object4 : CCafeClientDlg Object5 : CTaskMgr CBlockingSocket CBlockingSocket 1: SetComputer( ) 2: ListAll( ) 3: SetInfo( ) 4: SendMessage( ) 5: GetInfo( ) 6: RequestList( ) 7: GetWindowList( ) 8: SetInfo( ) 9: SendMessage( ) 10: GetInfo( ) Hình 2-37 Sequence Diagram Manage Application - List 2.2.5.19.2 Start: 65
- Hình 2-38 Sequence Diagram Ma Sequence Diagram 2-38 Hình : User Object1 : CAppListtab Object2(Server) : Object3(Client) : Object4 : CCafeClientDlg Object5 : CTaskMgr CBlockingSocket CBlockingSocket 1: SetComputer( ) 2: StartApp( ) 3: EnterInfo( ) 4: SetInfo( ) 5: SendMessage( ) 6: GetInfo( ) 66 7: StartApp( ) 8: StartApp( ) nage Application -Start nage Application 9: GetResult( ) 10: SetInfo( ) 11: SendMessage( ) 12: ShowResult( )
- 2.2.5.19.3 Stop: : User Object1 : CAppListtab Object2(Server) : Object3(Client) : Object4 : CCafeClientDlg Object5 : CTaskMgr CBlockingSocket CBlockingSocket 1: SetComputer( ) 2: ChooseApp( ) 3: StopApp( ) 4: SetInfo( ) 5: SendMessage( ) 6: GetInfo( ) 7: StopApp( ) 8: StopApp( ) 9: GetResult( ) 10: SetInfo( ) 11: SendMessage( ) 12: ShowResult( ) Hình 2-39 Sequence Diagram Manage Application – Stop 2.2.5.20 Use case Manage Service: 2.2.5.20.1 Show List 67
- : User Object1 : CSrvListtab Object4(Server) : Object5(Client) : Object6 : CCafeClientDlg Object7 : CTaskMgr CBlockingSocket CBlockingSocket 1: SetComputer( ) 2: ListAll( ) 3: SetInfo( ) 4: SendMessage( ) 5: GetInfo( ) 6: RequestServiceList( ) 7: GetServiceList( ) 8: SetInfo( ) 9: SendMessage( ) 10: GetInfo( ) 11: ShowList( ) Hình 2-40 Sequence Diagram Manage Service – Show List 68
- ChangeStartupService: Hình 2-41 Sequence DiagramManage Sequence 2-41 Hình : User Object1 : CSrvListtab Object2 : CChgSrvStartupDlg Object4(Server) : Object5(Client) : Object6 : CCafeClientDlg Object7 : CTaskMgr CBlockingSocket CBlockingSocket 1: SetComputer( ) 2: ChooseService( ) 3: ChooseStartupStyle( ) 4: GetStyle( ) 5: SetInfo( ) 6: SendMessage( ) 7: GetInfo( ) 69 8: ChangeStartup( ) Service – Change Service Startup 9: ChangeStartup( ) 10: GetResult( ) 11: SetInfo( ) 12: SendMessage( ) 13: ShowResult( )
- Change Status Hình 2-42 Sequence Diagram Mana Diagram 2-42 Sequence Hình : User Object1 : CSrvListtab Object3 : CChgSrvStatusDlg Object4(Server) : Object5(Client) : Object6 : CCafeClientDlg Object7 : CTaskMgr CBlockingSocket CBlockingSocket 1: SetComputer( ) 2: ChooseService( ) 3: ChooseStatusStyle( ) 4: GetStyle( ) 5: SetInfo( ) 6: SendMessage( ) 7: GetInfo( ) 70 8: ChangeStatus( ) ge Service –ChangeStatus ge Service 9: ChangeStatus( ) 10: GetResult( ) 11: SetInfo( ) 12: SendMessage( ) 13: ShowResult( )
- 2.2.6 Thiết kế cơ sở dữ liệu Hình 2-43 Cơ sở dữ liệu Category STT Tên Thuộc tính Mô tả 1 MALOAI Số nguyên 2 TENLOAI Text tên lọai thức ăn, nước uống Bảng 2-1 Category DailyReport STT Tên Thuộc tính Mô tả 1 PC_NO Text Giờ lúc khách hàng bắt đầu 2 START_TIME Ngày giờ sử dụng máy Giờ lúc khách hàng kết thúc 3 END_TIME Ngày giờ sử dụng máy 4 USERNAME Text tiền khi khách hàng sử dụng 5 ORDER_FEE số thực các dịch vụ có liên quan 6 WS_FEE số thực tiền phí sử dụng máy 7 TOTAL_FEE số thực tổng phí 8 ID_SERVICE Text Bảng 2-2 Daily Report DEBIT_DETAIL STT Tên Thuộc tính Mô tả 71
- 1 ID_DEBIT số nguyên 2PC_NO Text 3 USERNAME Text Giờ lúc khách hàng bắt 4START_TIMENgày giờ đầu sử dụng máy Giờ lúc khách hàng kết 5 END_TIME Ngày giờ thúc sử dụng máy 6 TOTAL_FEE số thực tổng phí Bảng 2-3 Bảng Debit_Detail DEBIT_LIST STT Tên Thuộc tính Mô tả 1ID số nguyên 2 NAME Text Tên khách nợ 3 ADDRESS Text 4 PHONE Text 5TOTAL_FEE số thực Tổng tền phải trả Tiền khách có thể trả 6 PREPAY số thực trước Bảng 2-4 Debit List DISH STT Tên Thuộc tính Mô tả 1MA số nguyên 2 DESCRIPTION Text Tên món thức ăn Loại thức ăn, nước 3MALOAI số nguyên uống 4PRICE số thực giá cả Bảng 2-5 Dish FEE_DAY STT Tên Thuộc tính Mô tả 1 ID_TABLE Text 2 BEGIN_TIME Ngày giờ giờ bắt đầu 3 END_TIME Ngày giờ giờ kết thúc 4 FEE_HOUR số thực Bảng 2-6 Fee-Day 72
- LOGIN STT Tên Thuộc tính Mô tả 1PC_NO Text 2 USERNAME Text 3PASSWORD Text 4 START_TIME Ngày giờ 5 END_TIME Ngày giờ 6 FEE số thực 7 ID_SERVICE Text Bảng 2-7 Login LOGIN_SERVICE STT Tên Thuộc tính Mô tả 1ID Text 2 MA_DISH số nguyên 3 AMOUNT số nguyên Bảng 2-8 Login Service MEMBER STT Tên Thuộc tính Mô tả 1 USERNAME Text 2PASSWORD Text 3 ADDRESS Text 4 TELEPHONE Text 5 FEE số thực 6PRIORITY số nguyên Bảng 2-9 Member MONTH_REPORT STT Tên Thuộc tính Mô tả 1 DATE Ngày giờ 2 PC_NO Text 3 TOTAL_FEE số thực Bảng 2-10 Month Report TABLE_DAY STT Tên Thuộc tính Mô tả 1 ID_TABLE Text 2 DAY Ngày giờ Bảng 2-11 Table Day 73
- 2.2.7 Thiết kế màn hình : 2.2.7.1 Thiết kế màn hình trên Client: 2.2.7.1.1 Màn hình Screen: Hình 2-44 Màn hình Screen 2.2.7.1.2 Màn hình Chính Client 74
- Hình 2-45 Màn hình chính Client Hình 2-46 Màn hình Order phí Client 2.2.7.2 Thiết kế màn hình trên Server: 2.2.7.2.1 Tab WorkStation: 75
- Hình 2-47 Màn hình Server – WorkStation 2.2.7.2.2 Tab Service: 76
- Hình 2-48 Màn hình Server – Service 2.2.7.2.3 Tab Administration: Hình 2-49 Màn hình Server – Keylock 77
- Hình 2-50 Màn hình Server – Keylog Hình 2-51 Màn hình Server – Message 78
- Hình 2-52 Màn hình Server – Apllication Hình 2-53 Màn hình Server – Service 79
- Hình 2-54 Màn hình Server – Snapshot 2.3 Cài đặt và thử nghiệm: 2.3.1 Cài đặt: Ứng dụng Server và CafeClient được phát triển sử dụng các công cụ và môi trường sau: + Công cụ phân tích và thiết kế: Rational Rose 2003 + Môi trường cài đặt ứng dụng: Windows XP Professional + Môi trường lập trình: Microsoft Visual Studio 6.0 2.3.2 Thử nghiệm: Chương trình được cài đặt thử nghiệm trên phòng máy của trung tâm mạng Máy Tính Nhất Nghệ - đường Bà Huyện Thanh Quan - với kết quả như sau:. STT Tính năng thử nghiệm Đánh giá 1 Kết nối Tốt Tính cước và các dịch vụ liên 2 quan Tốt 3 Quản trị từ xa Tốt 4 Chụp màn hình tĩnh Tốt 5 Chụp màn hình động Tốt Tùy thuộc vào thiết lập máy phía 6 Policy Client 80
- Chương 3 Các kỹ thuật lập trình 3.1 Kỹ thuật lập trình sự kiện và hook Trong quá trình thực hiện phần mềm, có một yêu cầu quản trị hệ thống là người quản trị cần biết lúc này người dùng đang gõ nội dung gì trên bàn phím hoặc anh ta có nhu cầu khóa tạm thời bàn phím hay một số phím nhất định. Các nhu cầu đó dẫn đến tình huống cần một cơ chế quản lý và kiểm soát bàn phím. Trong hệ thống Windows, có một cơ chế đáp ứng như thế : cơ chế hook. 3.1.1 Sự kiện và thông điệp trên HĐH Windows Trước hết, ta phải hiểu thêm về cơ chế thông điệp của hệ điều hành Windows. Đây là cơ chế cho phép các ứng dụng phân loại, lưu trữ, đáp lại tương tác với người dùng cũng như là tương tác lẫn nhau. * Hàng đợi thông điệp : Để lưu trữ, phân loại, tương tác Hệ điều hành Windows xây dựng hàng đợi thông điệp. Hai loại hàng đợi thông điệp dùng cho mục đích này là: o Hàng đợi hệ thống (System queue). o Hàng đợi ứng dụng (Application queue). Windows có các trình điều khiển thiết bị (Drivers) chịu trách nhiệm cho các dịch vụ ngắt từ thiết bị phần cứng mouse và keyboard. Tại mỗi thời điểm ngắt phát sinh, các Driver này gọi một điểm vào (hàm) đặc biệt trong USER.EXE để chỉ ra rằng một sự kiện vừa xảy ra. Các sự kiện mouse, bàn phím khi xảy ra đều trước hết được lưu vào hàng đợi hệ thống. Mọi tiến trình trong hệ thống đều chia sẻ hàng đợi. Hàng đợi hệ thống chỉ làm một nhiệm vụ duy nhất là ghi nhận các sự kiện mouse, bàn phím (nhấn, rê mouse, nhấn bàn phím ) khi có. 81
- Hình 3-1 Hàng đợi ứng dụng Khi một tiến trình được khởi tạo, một hàng đợi đại diện cho nó được tạo ra, hàng đợi này (đôi khi được gọi là hàng đợi tác vụ) được dùng để chứa những thông điệp sẽ được gởi cho các cửa sổ của ứng dụng. Những thông điệp này là những thông điệp được gởi một cách tường minh bằng một trong hai hàm sau : o PostMessage o PostAppMessage Ứng dụng có thể dùng hai hàm là GetMessage và PeekMessage do Windows cung cấp để khảo sát hàng đợi của mình. Hai hàm này cho phép ứng dụng lấy một thông điệp ra khỏi hàng đợi để từ đó phân loại và có những hồi đáp thích hợp với người dùng. 3.1.2 Hook là gì ? Hook là một cơ chế xử lý thông điệp của hệ thống mà một ứng dụng có thể cài đặt một đoạn lệnh (subroutine) để theo lưu thông thông điệp trên hệ thống và xử lý một số dạng thông điệp nào đó trước khi các thông điệp đến được thủ tục ở cửa sổ đích. 3.1.3 Đặc tính của hook: Hook có xu hướng làm chậm hệ thống vì chúng gia tăng số lượng công việc xử lý của hệ thống cho mỗi thông điệp. Chỉ nên cài đặt hook khi cần thiết, và tháo bỏ ngay khi không dùng nữa. 82
- 3.1.4 Các khái niệm trong hook: 3.1.4.1 Hook chains: Hệ thống hỗ trợ nhiều loại hook; mỗi dạng cung cấp khả năng truy cập đến khía cạnh khác nhau của cơ chế xử lý thông điệp. Chẳng hạn, ứng dụng có thể dùng WM_MOUSE hook để kiểm soát lưu thông thông điệp của các thông điệp về mouse. Hệ thống duy trì một hook chain (dãy các hook) riêng rẽ cho mỗi loại hook. Một hook chain là một danh sách các con trỏ trỏ đến các hàm do ứng dụng định nghĩa, đặc biệt riêng gọi là các hook procedure (thủ tục hook). Khi một thông điệp phát sinh mà liên quan đến một loại hook, hệ thống chuyền thông điệp cho mỗi hook procedure tham chiếu từ hook chain, hết cái này đến cái khác. Hoạt động một hook procedure thực hiện tùy thuộc vào loại hook quy định. Các hook procedure cho một số loại hook chỉ có thể quan sát các thông điệp; số còn lại có thể chỉnh sửa thông điệp hay chặn quá trình chuyền thông điệp trong hook chain, ngăn thông điệp đến được hook procedure kế tiếp hoặc cửa sổ đích. 3.1.4.2 Hook procedure Để tận dụng khả năng của mỗi loại hook, hệ thống cung cấp một hook procedure và sử dụng hàm SetWindowsHookEx để cài đặt hook procedure vào trong hook chain liên quan. Hook procedure phải theo công thức: LRESULT CALLBACK HookProc( int nCode, WPARAM wParam, LPARAM lParam ); Có thể đặt tên tùy ý, không cần phải đúng là HookProc cho hook procedure. Tham số nCode là mã hook mà hook procedure dùng để quyết định thao tác thực hiện. Giá trị mã hook tùy thuộc vào loại hook; mỗi loại lại có bộ mã hook mang tính chất riêng của nó. Các giá trị của tham số wParam và lParam tùy thuộc 83
- mã hook, nhưng chúng đặc biệt chứa thông tin về thông điệp được gởi hay chuyển (post). Hàm SetWindowsHookEx luôn cài đặt một hook procedure ở đầu hook chain. Khi một sự kiện xảy ra mà được quan sát bởi một loại hook, hệ thống sẽ gọi thủ tục ở đầu hook chain liên quan đến hook. Mỗi hook procedure trong chain quyết định có nên chuyển sự kiện sang thủ tục kế tiếp. Một hook procedure chuyển sự kiện sang thủ tục kế bằng cách gọi CallNextHookEx. Chú ý các hook procedure cho một số loại hook chỉ có thể quan sát thông điệp mà thôi. Hệ thống chuyển thông điệp cho mỗi hook procedure, mặc cho mỗi thủ tục có gọi CallNextHookEx. Một hook toàn cục (global hook) kiểm soát các thông điệp cho mọi tiểu trình trên cùng desktop với tiểu trình gọi hook. Một hook riêng cho tiểu trình (thread- specific hook) kiểm sóat các thông điệp cho chỉ riêng tiểu trình đó thôi. Một hook procedure toàn cục có thể được gọi trong ngữ cảnh của bất kỳ ứng dụng trên cùng desktop với tiểu trình gọi, vì vậy thủ tục được gọi phải ở trong một module thư mục liên kết động (dynamic linked library DLL) riêng rẽ. Một hook procedure riêng cho tiểu trình chỉ được gọi trong ngữ cảnh của tiểu trình liên quan thôi. Nếu ứng dụng cài đặt hook procedure một trong những tiểu trình của nó, hook procedure có thể trong cùng module với phần mã còn lại của ứng dụng hay trong một DLL. Nếu một ứng dụng cài đặt hook procedure cho một tiểu trình của một ứng dụng khác, thủ tục phải ở trong DLL. 3.1.4.3 Các loại hook Mỗi loại hook cho phép ứng dụng quan sát các khía cạnh khác nhau của cơ chế xử lý thông điệp của hệ thống. Các loại hook khả dụng là : • WH_CALLWNDPROC và WH_CALLWNDPROCRET Hooks • WH_CBT Hook • WH_DEBUG Hook • WH_FOREGROUNDIDLE Hook 84
- • WH_GETMESSAGE Hook • WH_JOURNALPLAYBACK Hook • WH_JOURNALRECORD Hook • WH_KEYBOARD_LL Hook • WH_KEYBOARD Hook • WH_MOUSE_LL Hook • WH_MOUSE Hook • WH_MSGFILTER và WH_SYSMSGFILTER Hooks • WH_SHELL Hook Trong các hook kể trên, ta chỉ cần chú ý ba hook dành cho xử lý sự kiện bàn phím WH_GETMESSAGE, WH_KEYBOARD, WH_KEYBOARD_LL. 3.1.4.3.1 WH_GETMESSAGE Hook Hook cho phép quan sát các thông điệp sẽ trả về bởi các hàm GetMessage và PeekMessage, có thể dùng hook để quan sát các dữ liệu nhập từ mouse và bàn phím và các loại thông điệp khác từ hàng đợi thông điệp. 3.1.4.3.2 WH_KEYBOARD_LL Hook Cho phép kiểm soát các sự kiện nhập từ bàn phím sẽ được chuyển đi trong hàng đợi thông điệp. 3.1.4.3.3 WH_KEYBOARD Hook Cho phép kiểm soát dòng lưu thông các thông điệp WM_KEYDOWN, WM_KEYUP sẽ trả bởi hàm GetMessage hay PeekMessage. Hook cũng có thể được dùng để kiểm soát các sự kiện nhập từ bàn phím sẽ được chuyển đi trong hàng đợi thông điệp. 3.1.5 Tiếp cận vấn đề: Như vậy, ta phải tạo một hook có khả năng chặn bắt các sự kiện bàn phím, ghi nhận, cho phép hoặc hủy bỏ trước khi các thông điệp bàn phím đến được cửa sổ 85
- đích. Trong các loại hook nêu trên, ta thấy các loại hook phù hợp là: WH_GETMESSAGE, WH_KEYBOARD, WH_KEYBOARD_LL. Tuy nhiên, mục tiêu đề ra là làm thế nào để kiểm soát bàn phím mà thôi, WH_GETMESSAGE kiểm soát hết các thông điệp, đồng thời hạn chế lớn nhất là WH_GETMESSAGE không có tính năng lọc bỏ thông điệp. Như vậy, ta chọn được hai hook WH_KEYBOARD, WH_KEYBOARD_LL. Ta chọn WH_KEYBOARD vì dễ cài đặt hơn, tương thích với nhiều phiên bản hệ điều hành Windows. Do chức năng khóa bàn phím là chức năng có nhiều kỹ thuật khá thú vị, nên quá trình cài đặt chức năng này sẽ được đề cập trước. 3.1.5.1 Tinh chế 0: Xây d•ng m•t •ng d•ng ••n gi•n cài ••t m•t hook toàn c•c. Khi •ng d•ng ch•y, phím ‘e’ trên bàn phím s• b• vô hi•u hóa (không gõ •••c n•a). Cài đặt hook toàn cục, ta cần viết các hàm cài đặt, gở bỏ hook và hook procedure trong một module riêng, gọi là DLL (thư viện liên kết động). Trước hết, ta cần khảo sát các hàm cài đặt, gở bỏ hook do Windows cung cấp. Các hàM API này được nêu rõ trong Phụ lục Các hàm API hữu ích sử dụng trong chương trình gồm: SetWindowsHookEx (cài đặt hook), UnhookWindowsHookEx (gở bỏ hook), CallNextHookEx (truyền cho hook kế). Các hàm API của Windows từ đây trở đi khi được đề cập đến nếu được sử dụng nhiều trong chương trình, sẽ được nêu rõ trong Phụ lục Các hàm API hữu ích sử dụng trong chương trình. Xây dựng hook procedure: Đây là lúc thích hợp để đề cập việc xây dựng hàm quan trọng nhất, hook procedure. Hook procedure là một callback function, tức là một hàm chỉ được gọi bởi Windows mỗi khi có sự kiện ứng với hàm xảy ra Các hook procedure đều có dạng sau: LRESULT CALLBACK HookProc( int nCode, WPARAM wParam, 86
- LPARAM lParam ); Ta cần sử dụng WH_KEYBOARD nên ta sẽ khảo sát cụ thể hook procedure cho WH_KEYBOARD: LRESULT CALLBACK KeyboardProc( int code, WPARAM wParam, LPARAM lParam ); code : xác định cách thức hook procedure xử lý thông điệp, nó là một trong hai giá trị sau : HC_ACTION : Thông điệp đã được lấy ra khỏi hàng đợi thông điệp. wParam và lParam chứa thông tin về thông điệp mà hook procedure nhận được. HC_NOREMOVE : wParam và lParam mang thông tin của thông điệp, và thông điệp vẫn còn trong hàng đợi (ứng dụng gọi PeekMessage với tùy chọn PM_NOREMOVE). Nếu code âm, hook procedure phải chuyển thông điệp đi bằng cách gọi hàm CallNextHookEx và trả về kết quả nhận được. wParam : chứa mã phím ảo của phím được nhấn. lParam : cho biết số lần lặp lại, mã quét, cờ mở rộng, mã ngữ cảnh, cờ trạng thái trước của phím, và cờ chuyển trạng thái: 0-15 cho biết số lần lặp phím, là số lần nhấn phím được tính khi người dùng giữ phím. 16-23 cho biết mã quét. 25-28 dành riêng. 29 cho biết mã ngữ cảnh. Giá trị 1 nếu phím ALT được nhấn, 0 nếu ALT nhả 30 cho biết trạng thái phím trước đó. Giá trị 1 nếu phím được nhấn trước khi thông điệp được gởi, 0 nếu ngược lại. 87
- 31 cho biết trạng thái chuyển đổi. 0 nếu phím đang nhấn, 1 nếu phím được thả. Tới đây, ta đã vượt qua một lượng lớn kiến thức khá thú vị về cơ chế hook. Đã đến lúc làm một việc gì đó cụ thể, ta cài đặt bài tóan nêu ở Tinh chế 0: Xây dựng các hàm cài đặt gở bỏ: quy tắc viết hàm theo module DLL, cách nạp một DLL vào bộ nhớ và thực thi, xem chi trong phần mã nguồn chương trình. Ở đây, ta chỉ đề cập đến cách hàm hoạt động mà thôi. Hàm cài đặt: LRESULT __declspec(dllexport) InstallKeyHook() Cài đặt một WH_KEYBOARD để xử lý thông điệp bàn phím và trả về handle hook cài đặt thành công hoặc lỗi nếu thất bại. Hàm gở bỏ: LRESULT __declspec(dllexport) UninstallKeyHook() Gở bỏ WH_KEYBOARD hook đã cài đặt, trả về mã thông báo kết quả. Hook procedure : LRESULT CALLBACK KeyboardProc(INT nCode, WPARAM wParam, LPARAM lParam) Ta chỉ xử lý khi thông điệp được lấy ra khỏi hàng đợi và chỉ xử lý một thông điệp WM_KEYDOWN mà thôi (khi lọc bỏ thông điệp WM_KEYDOWN thì thông điệp WM_KEYUP sẽ không được phát sinh, xem chi tiết về thông điệp bàn phím trong Phụ lục Sự kiện bàn phím). Hai thông điệp WM_SYSKEYDOWN và WM_SYSKEYUP cũng tương tự như thế. Thử nghiệm: Chương trình chạy hoạt động tốt nhưng khi ta thay đổi nhỏ như sau: cố truyền một biến cho DLL, biến này cho biết mã phím ảo của phím sẽ bị chặn, chẳng hạn, ‘e’, và truyền cho DLL như sau: SetX(‘e’); //SetX là hàm đặt biến trong DLL. và trong DLL khai báo một biến toàn cục như sau: WPARAM x; 88
- thì chương trình sẽ mất tác dụng khi ứng dụng của ta mất focus (không phải là cửa sổ đang kích họat). Điều này không chấp nhận được vì ứng dụng ta mong muốn cần phải chặn bắt các sự kiện bàn phím khi người dùng đang sử dụng. Hình 3-2 Tinh chế 0 3.1.5.2 Tinh chế 1: Xây d•ng m•t •ng d•ng cài ••t m•t hook toàn c•c. Khi •ng d•ng ch•y, tùy theo phím ng••i dùng gõ vào mà •ng d•ng s• khóa phím •ó. Để giải quyết vấn đề, ta cần phải tìm hiểu kỹ cơ chế hoạt động cũng như tải nạp một module DLL vào bộ nhớ khi ứng dụng cần. Điều cốt lõi ta cần biết chính là không gian địa chỉ. Khi một DLL toàn cục được thực thi, nó sẽ thực thi trong ngữ cảnh của tiến trình mà có sự kiện nó cần hook đang xảy ra. Vì đây là một DLL, nó sẽ có một bản sao riêng rẽ của những dữ liệu cần dùng của nó (trong trường hợp ta khảo sát, đó là biến toàn cục x) cho mỗi tiến trình. Vì vậy, mỗi lần hook procedure được gọi, DLL sẽ nạp vào không gian địa chỉ của tiến trình cần hook, và một loạt các dữ liệu mà DLL dùng sẽ được khởi tạo mới (chẳng hạn các biến toàn cục khai báo ở mức độ tập tin như biến x đã nêu trên). Vì vậy, ta phải làm một cách nào đó mà các dữ liệu ta cần (biến x) có thể dùng cho mọi thể hiện của DLL. Điều này có thể thực hiện được bằng cách sử dụng đọan không gian địa chỉ chia sẻ (shared segment), xem thêm chi tiết về vấn đề này trong phần Phụ lục DLL – thư viện liên kết động. 89
- Khi đó, do các biến ta cần đều được đặt trong đoạn không gian địa chỉ chia sẻ, các thể hiện của DLL được nạp trong mỗi tiến trình đều “hiểu” (đọc được giá trị trong bản gốc DLL nạp do ứng dụng của ta đặt). Để khai báo một phân đoạn không gian địa chỉ chia sẻ, ta làm như sau: #pragma data_seg(“.VAN”) //Các biến cần sử dụng chung #pragma data_seg() #pragma comment(linker, “/section:.VAN,rws”) với “.VAN” là tên đặt gợi nhớ tùy ý cho phân đoạn (nhưng không được dài hơn 8 ký tự). #pragma comment ở trên đặt thêm một tùy chọn biên dịch cho các tập tin biên dịch .OBJ. Đến đây, mọi việc lại trở nên quá dễ dàng với phân đọan chia sẻ ta vừa tạo ra. Ta chỉ việc tạo ra 255 biến trạng thái (kể cả các ký tự điều khiển và mở rộng, có thể có tới 256 ký tự). Các biến này lưu trữ trạng thái của phím như sau: #define MAX_KEYS_LOCK 255 static BOOL g_bHook[MAX_KEYS_LOCK] với FALSE cho biết phím chưa khóa TRUE cho biết phím đã khóa đặt mảng các biến vào trong phân đọan vừa tạo trên và chỉnh sửa lại hook procedure KeyboardProc: Thế là ta hoàn tất vấn đề chính. Việc còn lại chỉ đơn giản là thiết lập hàm ghi giá trị biến trong DLL và gọi nó trong ứng dụng Thử nghiệm tinh chế 1: Chương trình hoạt động khá tốt nhưng ta vẫn chưa đề cập đến các phím chức năng (ví tổ hợp Alt-Tab ). Thật vậy, chương trình hoàn toàn bất lực trước các phím chức năng vì ta không thiết kế chức năng “nhập” các phím chức năng, mà cho dù có, ta cũng không “bắt” được. Điều này không chấp nhận được vì ứng dụng ta mong muốn cần phải chặn bắt các sự kiện bàn phím khi người dùng đang sử dụng. 90
- Hình 3-3 Tinh chế 1 3.1.5.3 Tinh chế 2: Xây d•ng m•t •ng d•ng cài ••t m•t hook toàn c•c. Khi •ng d•ng ch•y, cho phép vô hi•u hóa b•t k• phím nào trên bàn phím. Để giải quyết vấn đề này, ta cần xem xét lại khả năng của hook WH_KEYBOARD. Hook không có khả năng chặn bắt các tổ hợp phím như: Alt- Tab Vì vậy, ta đành phải sử dụng hook khả dĩ cuối cùng là hook WH_KEYBOARD_LL. Tuy nhiên, hook là một hook mới có từ Windows NT/2000/XP trở về sau. Đây là một hook rất mạnh nhưng cách dùng cũng như tham số đầu vào khác rất nhiều so với WH_KEYBOARD. Do đó, ta phải tinh chỉnh lại hook procedure nếu không muốn thay đổi toàn bộ cài đặt từ trước. Khảo sát hook procedure của WH_KEYBOARD_LL : LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ); Ý nghĩa tham số: 91
- [in] nCode: xác định cách thức xử lý thông điệp. Nếu nCode âm, phải chuyển thông điệp sang hook procedure kế, và trả về kết quả nhận được, chỉ có thể là giá trị: HC_ACTION wParam và lParam chứa thông tin về thông điệp bàn phím. wParam: xác định loại thông điệp. Đó là: WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, và WM_SYSKEYUP. lParam: trỏ đến cấu trúc KBDLLHOOKSTRUCT. Cấu trúc KBDLLHOOKSTRUCT như sau: typedef struct { DWORD vkCode; DWORD scanCode; DWORD flags; DWORD time; ULONG_PTR dwExtraInfo; } KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT; Có ý nghĩa như trong Phụ lục Sự kiện bàn phím. Ý nghĩa tham số: [in] vkCode : mã phím ảo từ 1-254. scanCode: mã quét phần cứng. flags: cờ phím mở rộng, cờ sự kiện thêm vào, mã ngữ cảnh, và cờ chuyển đổi trạng thái. Ứng dụng dùng các giá trị sau để kiểm tra cờ nhấn phím Value Purpose LLKHF_EXTENDED Kiểm tra cờ mở rộng. LLKHF_INJECTED Kiểm tra cờ thêm sự kiện. LLKHF_ALTDOWN Kiểm tra mã ngữ cảnh. LLKHF_UP Kiểm tra cờ chuyển trạng thái. 92
- Bảng 3-1 Giá trị khảo sát phím mở rộng 0 cho biết phím có là phím mở rộng hay không, chẳng hạn như phím chức năng hay phím bên bảng số (numpad). Giá trị 1 nếu đúng, 0 nếu sai. 1-3 Dành riêng. 4 Cho biết sự kiện này có phải do được thêm vào không (chứ không phải do từ bàn phím gõ). Giá trị 1 nếu đúng, 0 nếu sai. 5 Cho biết mã ngữ cảnh, phím alt có được nhấn hay không. Giá trị 1 nếu đúng, 0 nếu sai. 6 Dành riêng. 7 Cho biết trạng thái phím. Giá trị 0 nếu phím nhấn và một nếu phím được thả. time Cho biết tem thời gian của thông điệp. dwExtraInfo Cho biết các thông tin đi kèm thêm với thông điệp. So sánh với các tham số của WH_KEYBOARD, ta cần giả lập wParam, lParam của WH_KEYBOARD từ wParam, lParam của WH_KEYBOARD_LL. wParam: khá dễ dàng, wParam của WH_KEYBOARD chính là vkCode trong cấu trúc KBDLLHOOKSTRUCT do lParam của WH_KEYBOARD_LL trỏ đến. lParam: phức tạp hơn một chút, ở đây ta phải giả lập lại giá trị DWORD của lParam trong WH_KEYBOARD từ cấu trúc KBDLLHOOKSTRUCT do lParam của WH_KEYBOARD_LL trỏ đến. Hàm MakeFakelParam sẽ giúp ta làm điều này: LPARAM MakeFakelParam(PKBDLLHOOKSTRUCT pKb) Hàm có tác dụng chuyển đổi giá trị lParam trong cấu trúc KBDLLHOOKSTRUCT sang giá trị lParam của WH_KEYBOARD. Tuy thế, mọi việc vẫn chưa kết thúc. Rắc rối xảy ra khi ta nhấn phím ALT. Phím ALT sẽ nhận biết được nếu ta nhấn phím mà không kèm theo một phím khác. 93
- Phím sẽ không biết được nếu ta nhấn kèm với phím khác vì khi đó, driver bàn phím sẽ thông dịch phím ALT thành mã ngữ cảnh. Vì vậy, đối với riêng tình huống này ta phải xử lý riêng: So sánh thêm mã ngữ cảnh: if( (g_bHook[VK_LMENU]) || (g_bHook[VK_RMENU]) ) if(p->flags & LLKHF_ALTDOWN) // co nhan kem alt voi phim nay return 1; Như vậy bài tóan tinh chế 2 đã được giải quyết hoàn chỉnh. chèn hình Thử nghiệm: Chương trình chạy tốt yêu cầu đề ra. Lưu ý rằng do tính chất là một hook cấp thấp, nên vấn đề nhận biết số lần lặp lại phím khá phức tap. Ta có thể bỏ qua việc này vì ứng dụng thực sự của ta không cần đến.Vấn đề còn lại là ghi nhận phím, một keylogger đơn giản, ít phức tạp hơn nhiều. Hình 3-4 Tinh chế 2 3.1.5.4 Tinh chế 3: Xây d•ng m•t •ng d•ng cài ••t m•t hook toàn c•c. Khi •ng d•ng ch•y, xu•t ra màn hình ký t• ng••i dùng gõ. Ta cần lưu ý kỹ thuật lập trình truyền thông điệp chứa dữ liệu ký tự phím gõ từ hook procedure đến cửa sổ xử lý. Điều này có thể thực hiện được khi lúc ban đầu 94
- khởi tạo hook ta cần cho hook biết cần kiểm sóat bao nhiêu phím (cả bàn phím), handle cửa sổ chính, loại thông điệp (ứng dụng ta không cần quan tâm nên ta chỉ cần thông điệp WM_KEYDOWN), các loại cửa sổ cần kiểm sóat (mọi cửa sổ), các phím kết hợp kèm theo (ta không quan tâm). Tất cả các thông tin trên được gọi là một bộ kiểm sóat (entry). Hàm LogKeyboard sẽ giúp ta làm điều này: LRESULT CKeyLogClient::LogKeyboard(HWND hWnd) Hàm sẽ gọi hàm AddKeyEntry, là một hàm trong DLL. Hàm có tác dụng lưu trữ các dữ liệu trên. Khi đó, cài đặt hook xong ta chỉ việc đợi kết quả gởi tới cửa sổ xử lý. Dĩ nhiên, hook procedure cần sửa lại để thông báo cho cửa sổ cài đặt hook biết có thông điệp mã phím cần xử lý (sử dụng hàm PostMessage gởi thông điệp tự định nghĩa cho cửa sổ chính với handle cửa sổ chính nhận được từ hàm LogKeyboard). LRESULT CALLBACK KeyboardProc(INT nCode, WPARAM wParam, LPARAM lParam) Thử nghiệm: Như vậy, ta đã hoàn tất được mục tiêu đề ra ban đầu. Mặc dù chương trình hoàn chỉnh phải bao gồm nhiều kỹ thuật lập trình thú vị khác, nó lại không nằm trong phạm vi tìm hiểu mà mục tiêu ta cần. Chương trình hoàn chỉnh còn có thêm khả năng sử dụng hook cho đồng thời tối đa 256 tiến trình và tối đa 1024 bộ kiểm sóat. Phần việc còn lại chỉ cần thay đổi một ít mã nguồn để tích hợp vài chương trình chính. 95
- Hình 3-5 Tinh chế 3 3.2 Xây dựng màn hình che: Trong quá trình thực hiện phần mềm, có một yêu cầu cần thiết cho chương trình quản lý phòng máy là cần phải ngăn chặn người dùng không dùng máy khi chưa đăng ký với người quản trị để sử dụng. Một điều thực tế hiển nhiên là các máy tính trong phòng máy phải luôn bật máy sẵn sàng. Vì vậy, ta cần xây dựng một màn hình che trên màn hình để người dùng không thể tương tác với máy. 3.2.1 Phân tích sơ lược: Ta nhận thấy rằng để tương tác với máy tính, thông thường người dùng sẽ sử dụng hai thiết bị tương tác là mouse và bàn phím. Ta không cần quan tâm về các loại thiết bị tương tác khác vì thông thường các phòng máy chỉ cần hai thiết bị nêu 96
- trên là đủ. Vì vậy, ta sẽ xem xét các tương tác của người dùng để sử dụng máy tính bằng hai thiết bị trên. Sau khi khảo sát, quy trình sử dụng máy thông thường sẽ là: 1. Bật máy lên 2. Nếu có icon chương trình cần chạy trên desktop, kích hoạt chương trình. 3. Nếu chương trình không có trên desktop, người dùng sẽ lục tìm trên máy bằng nhiều cách khác nhau như : a. Nhấn Start, dò trên All Programs. b. Nhấn Start, chạy Run, mở gõ chương trình cần chạy. c. Chạy My Computer, dò chương trình trong cây thư mục. d. Mở Windows Explorer, dò chương trình trong cây thư mục. e. 4. Khi sử dụng xong chương trình, người dùng đóng chương trình lại. 5. Quay trở lại bước 2 Vòng lặp sẽ xảy ra cho đến khi người dùng sử dụng xong máy tính. 6. Tắt máy tính. Các bước 1 và 6 có thể được bỏ qua. Ta sẽ xem xét các bước từ 2 đến 6. Dễ dàng nhận thấy rằng mọi tương tác của người dùng thông thường đều phải thông qua desktop. Nếu ta làm cách nào đó ngăn chặn việc tương tác của người dùng trên desktop, ta sẽ đạt được mục tiêu đề ra. Từ đây, ta sẽ đưa ra các khảo sát cụ thể cho mỗi thiết bị mouse và bàn phím. 3.2.1.1 Tương tác bằng mouse: Đây là thiết bị chủ yếu người dùng sẽ sử dụng để tương tác với máy tính. Phần lớn người dùng thông thường sẽ không biết sử dụng máy, hoặc sẽ rất khó khăn khi sử dụng máy mà không có mouse. Do tính phổ thông và cần thiết như thế, người dùng sẽ phụ thuộc rất nhiều vào mouse. Vẫn theo ý tưởng đề ra ở trên, ta để ý rằng thực chất desktop chỉ là một cửa sổ của Windows, trên đó, mọi ứng dụng sẽ được chạy (mọi cửa sổ ứng dụng được 97
- mở trên desktop đều là cửa sổ con của nó). Nếu có một cửa sổ nào đó nằm chồng lên trên desktop, và cửa sổ đó đang kích hoạt, thì người dùng sẽ tương tác với cửa sổ đó chứ không thể tương tác với desktop. Để có thể tương tác trở lại với desktop, người dùng phải click mouse trái lên trên desktop (trong trường hợp cửa sổ bình thường), nhấn nút Minimise trên thanh tiêu đề của cửa sổ (trong trường hợp cửa sổ bình thường hoặc đang phóng to hết cỡ). Điều gì sẽ xảy ra nếu người dùng không còn những khả năng trên : o không thể click chuột trái lên trên desktop vì cửa sổ đang được phóng to hết cỡ (maximized), che mất cả desktop và cả thanh taskbar . o không thể thu nhỏ cửa sổ lên trên thanh taskbar, phục hồi cửa sổ lại kích thước thông thường, và tắt cửa sổ đi vì cửa sổ không có thanh tiêu đề. Đến đây, ta đã thấy rõ cách làm. Điều duy nhất cần làm bây giờ là : o tạo một cửa sổ không có thanh tiêu đề. o kích hoạt cửa sổ mỗi khi máy vừa khởi động xong. o “căng” kích cở của cửa sổ sao cho vừa khít với desktop. Để làm được điều này, ta sẽ sử dụng các kỹ thuật và hàm thông thường được cung cấp sẵn bởi Windows mà ta sẽ đề cập kỹ ở phần cài đặt. Bây giờ, đã đến lúc đề cập đến bàn phím. 3.2.1.2 Tương tác với bàn phím: Đây là thiết bị quan trọng thứ hai sau mouse để người dùng tương tác với desktop. Phần lớn người dùng thông thường chỉ sử dụng bàn phím nhiều khi họ sử dụng máy tính là đánh văn bản. Trong phòng máy tính Café Internet, bàn phím được dùng để chat, nhập thông tin người dùng trong lúc lướt web Chỉ có một số nhỏ người dùng am hiểu rõ và ghi nhớ các phím tắt do Windows gán để tương tác với desktop. Chẳng hạn, xem bảng so sánh các thao tác bằng mouse và bàn phím qua hai thao tác hay dùng là mở Control Panel và shutdown máy: Bằng mouse Bằng bàn phím 98
- 1. Mở Control Panel 1. Mở Control Panel a. Nhấn Start a. Nhấn Win key, hoặc Ctrl-Esc b. Nhấn phím r, kích hoạt cửa sổ Run b. Chọn All Programs c. Gõ “control” trong ô Open (không có dấu “”) c. Chọn Control Panel d. Nhấn Enter 2. Shutdown máy : 2. Shutdown máy: a. Nhấn Start a. Nhấn Win key, hoặc Ctrl-Esc. b. Chọn Turn off b. Nhấn phím r, kích hoạt cửa sổ Run. Computer c. Gõ “shutdown /s /t 0” trong ô Open (không có c. Chọn tiếp Turn off dấu “”) d. Nhấn Enter Bảng 3-2 So sánh tương tác giữa mouse và bàn phím Tùy thuộc vào cấu hình các phiên bản Windows mà các bước thực hiện có thể khác đôi chút, ở đây ta sử dụng WindowsXP chế độ taskbar là “Start menu”, chế độ log off là “Using Welcome Screen”.) Nhìn chung các thao tác bằng bàn phím khá phức tạp hơn bằng mouse, tựu trung lại chỉ cần nhớ phím và tổ hợp phím thực thi, câu lệnh, và làm một việc duy nhất là gõ. Do vậy, ta chỉ cần làm một việc duy nhất là vô hiệu hóa toàn bộ phím bấm trên bàn phím là xong mà ta sẽ đề cập kỹ ở phần cài đặt. 3.2.2 Cài đặt: Ta sẽ thực hiện những bước đề ra như ở trong phần 1.2.1 Phân tích sơ lược lần lượt cho mỗi thiết bị. 3.2.2.1 Tương tác với mouse: Ta sẽ tạo một cửa sổ. Tuy nhiên, cửa sổ theo dạng tài liệu (document) như WinWord, Windows Explorer không phù hợp cho mục tiêu. Cái ta cần sẽ là một cửa sổ dạng hộp thoại (dialog), vì ta về sau có thể cần chèn hình ảnh giới thiệu. Vả lại, ta cần một cửa sổ càng đơn giản càng tốt (ít cấu hình sẵn), hỗ trợ thiết kế trực 99
- quan thì trong Microsoft Visual Studio 6.0 viết chương trình bằng MFC, loại project theo Dialog-based là thích hợp nhất. Sau khi tạo một hộp thoại xong, ta cần cho cửa sổ “nổi” lên trên tất cả cửa sổ khác kể cả desktop và thanh taskbar và “căng” kích cỡ chiếm hết cả màn hình. Hàm API SetWindowPos sẽ giúp ta điều này. Tuy thế, ta sẽ không gọi trực tiếp hàm API SetWindowPos mà gọi thông qua phương thức của CWnd, lớp cha của lớp cửa sổ thoại, SetWindowPos: Phương thức chỉ khác hàm API ở chỗ chỉ có 6 tham số ứng lần lượt với 6 tham số cuối của hàm API. Phương thức sẽ thực thi bằng cách gọi lại hàm API và thêm tham số đầu tiên của hàm API băng handle cửa sổ có sẵn cửa sổ lớp hộp thoại m_hWnd. Đến đây, có một vấn đề nhỏ cần giải quyết là lấy được kích thước của desktop, hay nói cách khác là độ phân giải của màn hình. Ta không thể lấy cố định kích thước, ví dụ là 800x600, vì mỗi màn hình sẽ được người dùng sẽ thay đổi độ phân giải cho phù hợp với mắt nhìn. Do vậy, có hai cách giải quyết : a. Đọc trực tiếp các giá trị độ dài và độ rộng của màn hình bằng hàm API GetSystemMetrics: Áp dụng hàm trong chương trình như sau: int xScrn = ::GetSystemMetrics(SM_CXSCREEN); int yScrn = ::GetSystemMetrics(SM_CYSCREEN); SetWindowPos(&wndTopMost, 0, 0, xScrn, yScrn, SWP_SHOWWINDOW); Đọan mã trên đặt trong phương thức khởi tạo của cửa sổ hộp thoại, tham số &wndTopMost nhằm đặt cửa sổ vào dãy thứ tự các cửa sổ dạng “nổi trội”, các tham số sau có ý nghĩa là dời cửa sổ về góc trên bên phải màn hình, độ rộng và dài bằng độ phân giải màn hình, kích hoạt và hiện cửa sổ. b. Đọc các giá trị độ rộng và dài từ hai hàm API CreateDC, GetDeviceCaps. Dùng cách này có tiện lợi khi hệ thống có nhiều màn hình hiển thị: 100
- hàm API CreateDC: tạo ngữ cảnh thiết bị hàm API GetDeviceCaps: lấy các thông số của thiết bị. Áp dụng mã vào chương trình như sau: HDC hScrDC; hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL); int xScrn, yScrn; xScrn = GetDeviceCaps(hScrDC, HORZRES); yScrn = GetDeviceCaps(hScrDC, VERTRES); //resize cho lon nhat . Day la topmost window SetWindowPos(&wndTopMost, 0, 0, xScrn, yScrn, SWP_SHOWWINDOW); Hai dòng đầu tạo một HDC cho thiết bị màn hình hiển thị, do tính chất đặc biệt của màn hình mà hàm chỉ cần nhận tham số tên “DISPLAY” là có thể trả về kết quả. Ba dòng kế tiếp có tác dụng lấy độ rộng và độ dài của màn hình. Dòng cuối là gọi phương thức SetWindowPos như cách 1. Có một lưu ý nhỏ ở đây là ta vẫn có thể sử dụng thay thế hàm SetWindowPos bằng một hàm API khác là MoveWindow. Để biết chi tiết hàm, xem thêm trong Phụ lục Các hàm API hữu ích sử dụng trong chương trình. Hàm API này tuy có chức năng tương tự với SetWindowPos nhưng hàm lại không có chức năng quản lý việc “nổi” lên trên cửa sổ khác.Mặc dù theo thiết kế ban đầu khi khởi động xong, chỉ có một cửa sổ màn hình che phủ toàn bộ màn hình, rất có khả năng người dùng nhanh tay kích hoạt một cửa sổ nào đó trên desktop. Khi ấy, sử dụng hàm MoveWindow lại không làm cửa sổ “nổi” lên trên tất cả các cửa sổ còn lại. Hàm SetWindowPos lại có thêm tác dụng hữu ích này. Thử nghiệm: Chương trình vô hiệu hóa tuyệt đối việc tương tác của người dùng với desktop bằng mouse. Chỉ còn lại một việc nữa phải làm là vô hiệu hóa bàn phím. 101
- Hình 3-6 Màn che mouse 3.2.2.2 Tương tác bằng bàn phím: Mục tiêu ban đầu là không cho người dùng gõ những phím tắt kích hoạt chương trình. Tuy nhiên, ta không cần vô hiệu hóa cả bàn phím. Điều này rất lãng phí công sức. Thực chất, ta thực hiện mục tiêu dưới điều kiện hoàn thành ngăn chặn tương tác với mouse. Vì vậy các loại tương tác làm cho xuất hiện các chương trình thông thường như Windows Explorer (Win key + E) không làm ta quan tâm vì các cửa sổ chương trình đó không thể “nổi” bằng cửa sổ màn hình che. Vì vậy, chỉ còn lại các loại phím và tổ hợp phím tắt “nhạy cảm” cấp thấp mà thôi. Các loại phím tắt đó là: o Win key : có tác dụng bật Start menu. o Alt + Tab : có tác dụng đổi cửa sổ đang hoạt động. o Alt + Esc : có tác dụng kích hoạt cửa sổ kế trên thanh taskbar. 102
- o Ctrl + Esc: có tác dụng tương tự Win key o Ctrl + Shift + Esc : có tác dụng bật Task Manager. o Esc : đây là vấn đề về kỹ thuật làm, theo thiết kế ta tạo một cửa sổ hộp thoại đơn giản, nên chịu tác dụng của phím Esc, có tác dụng tắt cửa sổ màn che. o Alt + F4 : có tác dụng tắt cửa sổ màn hình che. o Ctrl + Alt + Del : có tác dụng bật Task Manager, hay hộp lựa chọn tùy theo cấu hình Windows (đây là tổ hợp phím gây “nhức đầu” nhiều nhất, ta sẽ đề cập kỹ trong phần sau). o Ctrl + Shift + Esc : bật Task Manager. May mắn thay, trong 7 tổ hợp phím đầu, ta dễ dàng loại bỏ khi sử dụng kỹ thuật lập trình bằng hook, xem chi tiết về kỹ thuật này trong 3.1 Kỹ thuật lập trình sự kiện và hook và mã nguồn chương trình. Ta chỉ áp dụng xây dựng một hook đơn giản lọc bỏ trong quá trình đợi đăng nhập và loại bỏ khi đăng nhập xong. Tuy nhiên, với 2 tổ hợp phím cuối cùng, Ctrl + Alt + Del và Ctrl + Shift + Esc (về sau ta gọi tắt chỉ một mình tổ hợp Ctrl + Alt + Del vì tổ hợp Ctrl + Shift + Esc cũng có tính năng tương tự), khá phức tạp. Ta phải hiểu rõ cơ chế truyền gởi thông điệp Ctrl – Alt – Del. Hook bàn phím không thể bắt được tổ hợp phím Ctrl – Alt – Del ! Tại sao ? Vì chính bản thân hệ điều hành Windows không hề gởi tổ hợp phím này cho hook chain. Nó đã được chặn bắt và xử lý ở mức thấp hơn ở hệ thống và không bao giờ được gởi lên ứng dụng. Ứng dụng nếu có cài đặt cũng chỉ nhận được các phím Ctrl, Alt, và Del rời rạc chứ không phải là tổ hợp Ctrl – Alt – Del. Tổ hợp phím sau đó sẽ gởi đến cơ chế khởi động đăng nhập của Windows, gọi là Winlogon, gồm 3 thành phần : thành phần thực thi (“winlogon.exe”), thư viện liên kết động “Chứng thực và nhận dạng theo cơ chế đồ họa” (Graphical Identification and Authentication GINA) (“msgina.dll”), và các thành phần mạng. Tham khảo các tài liệu, ta tìm thấy các cách khống chế tổ hợp Ctrl – Alt – Del, một số cách dựa trên việc khống chế một trong hai thành phần đầu trong cơ chế khởi động đăng nhập của Windows như sau: 103
- • Giả lập “lừa” hệ điều hành rằng đang có một screensaver đang chạy, tổ hợp phím được gởi nhưng không kích hoạt Task Manager. Tuy nhiên, cách này chỉ có tác dụng ở các phiên bản hệ điều hành Win98, không có tác dụng trên WinXP. Cách này cũng rất hạn chế khi chỉ có tác dụng khi có thiết lập hệ thống phù hợp, một số tài liệu cho rằng cả phiên bản hệ điều hành Win98 cũng không có tác dụng !. • Vô hiệu hóa Task Manager bằng chính sách (policy). Cách này không hề xử lý ở “gốc”, chặn bắt thông điệp Ctrl – Alt – Del, mà xử lý ở “ngọn”, đặt chính sách hệ thống ngăn chặn kích hoạt Task Manager. Cách này đơn giản nhưng không dùng được vì thông điệp thông báo : Hình 3-7 Thông báo của policy về việc vô hiệu hóa Task Manager khá bực mình, lại còn làm xuất hiện Start Menu. • Bắt thông điệp ở tận “gốc” khi xây dựng driver thiết bị bàn phím. Lúc đó, phải sử dụng Device Development Kit (bộ phát triển thiết bị). Đây là lĩnh vực lập trình hoàn toàn mới, với thời gian nghiên cứu không cho phép, ta bỏ qua khả năng này. • Viết một GINA stub. GINA là một thư viện liên kết động mà Winlogon dùng để chứng thực người dùng. Đây là một cách khá hay, nhưng nó lại làm thay đổi cách đăng nhập của người dùng đồng thời vô hiệu hóa màn hình Welcome, và chớp màn hình mỗi khi người dùng nhấn Ctrl – Alt – Del. Tuy ta không sử dụng cách này nhưng có thể xem thêm về kỹ thuật này trong Phụ lục GINA stub – kỹ thuật xây dựng. • Tạo một desktop mới và chuyển sang desktop mới này. Vì kích hoạt Task Manager bằng tổ hợp phím Ctrl – Alt – Del chỉ làm xuất hiện Task Manager 104
- trên “Default” desktop (desktop cũ), nên trên desktop mới sẽ không có xuất hiện. Cách này khá hiệu quả khi ta xây dựng màn hình che bên desktop mới, người dùng đăng nhập vào thì trở lại desktop cũ. Khuyết điểm nhỏ của cách này là hơi phức tạp về mặt lý thuyết cài đặt chương trình, và người dùng đăng nhập vào thành công sẽ thấy Task Manager hiện ra mặc dù trước đó có vẻ việc nhấn Ctrl – Alt – Del không có tác dụng. Tuy ta không sử dụng cách này nhưng có thể xem thêm về kỹ thuật này trong Phụ lục Tạo thêm và sử dụng Desktop mới. • Kế thừa, trở thành lớp con của lớp cửa sổ SAS trong tiến trình Winlogon. Để làm được điều này, mã phải được “chích” (inject) vào tiến trình Winlogon và sau đó tạo lớp con kế thừa Windows Procedure. Kỹ thuật này không tương thích với Windows 95/98/Me. Ta sẽ sử dụng kỹ thuật này để vô hiêu hóa tổ hợp phím Ctrl – Alt - Del. Module xây dựng gồm có hai phần lớn : tạo lớp con kế thừa lớp cửa sổ SAS của Winlogon. * Tạo lớp con kế thừa lớp cửa sổ SAS của Winlogon: Hàm API SetWindowLong sẽ giúp ta thực hiện điều này: Áp dụng hàm vào trong chương trình: SetWindowLong(hWnd, GWL_WNDPROC, NewWindowProc); Lời gọi chỉ có tác dụng cho các cửa sổ được tạo bởi cùng ứng dụng gọi hàm (địa chỉ hàm NewWindowProc chỉ có nghĩa với tiến trình gọi hàm SetWindowLong). Như vậy, ta sẽ dùng một cách nào đó ánh xạ được điạ chỉ của NewWindowProc vào trong không gian địa chỉ của tiến trình ở xa và chuyển địa chỉ đó đến lời gọi hàm SetWindowLong. Để có thể hiểu cơ chế nạp một chương trình vào bộ nhớ, cũng như định nghĩa về không gian địa chỉ của tiến trình, xem thêm Phụ lục Quá trình nạp một hook DLL toàn cục. Bây giờ, ta sẽ bàn về kỹ thuật injection. * Kỹ thuật injection: 105
- Khả năng ứng dụng của kỹ thuật injection rất mạnh mẽ và hữu ích. Ưu điểm này cũng lại là khuyết điểm. Vì càng có nhiều khả năng ứng dụng mà không bị hạn chế, kỹ thuật injection đòi hỏi các lập trình viên cần phải lập trình cực kỳ cẩn thận các đọan mã mà họ sẽ “chích” vào tiến trình ở xa. Mọi hành động “chích” lầm sẽ dẫn đến hậu quả cực kỳ nguy hiểm như crash chương trình ở xa, treo máy Tuy nhiên, việc lập trình thành công bằng kỹ thuật injection sẽ gợi mở nhiều khả năng lập trình thú vị như : xem mật khẩu dạng * trên một cửa sổ khác, Hình 3-8 Ứng dụng xem mật khẩu từ cửa sổ khác điều khiển hoạt động của các tiến trình hệ thống Windows như : giấu tên tiến trình đang chạy trong hai tab Applications” và “Processes” của Task Manager, đặc biệt là ứng dụng mà ta cần là vô hiệu hóa Ctrl – Alt – Del. Vậy thực chất kỹ thuật injection là gì ? Kỹ thuật ánh xạ bộ nhớ (mã chương trình) vào trong không gian địa chỉ của một tiến trình ở xa được gọi là kỹ thuật injection. Việc injection có thể thực hiện bởi một trong những cài đặt sau: • Registry. Để “chích” một DLL vào một tiến trình, chỉ cần đơn giản thêm tên DLL đó vào trong khóa registry: HKLM\Software\Microsoft\Windows NT\ 106
- CurrentVersion\Windows\AppInit_DLLs:STRING chỉ hỗ trợ trên Windows NT trở lên. • Hook. Cách này hỗ trợ trên mọi phiên bản Windows. • Sử dụng CreateRemoteThread()/LoadLibrary(), chỉ đúng với Windows NT và cao hơn. • Sao chép mã trực tiếp vào tiến trình ở xa bằng WriteProcessMemory() và thực thi nó bằng hàm CreateRemoteThread(), chỉ đúng với Windows NT và cao hơn. Mức độ cẩn thận trong lập trình tăng dần từ trên xuống trong 4 cài đặt của kỹ thuật, tỉ lệ nghịch với việc tiêu tốn tài nguyên (giảm dần từ trên xuống). Cơ chế hook vẫn áp dụng được trong kỹ thuật này nhưng việc áp dụng nó khá tiêu tốn tài nguyên hệ thống. Ta sẽ thực hiện phương án cuối để áp dụng kỹ thuật injection cho cài đặt trong phần mềm. Phương án 3 cũng khả thi nhưng lại không ổn định, tùy thiết lập của máy mà phương án thành công hay không, có thể xem thêm phương án này trong mã nguồn chương trình. Ở đây, ta sẽ mô tả cài đặt cuối : Chương trình sử dụng cài đặt cuối qua hai hàm InjectCode, và EjectCode. InjectCode thực hiện việc sao chép dữ liệu và trong tiến trình của cửa sổ SAS. Các dữ liệu này là : InjectFunc, “khung” thực thi của tiểu trình, GetSASWnd, tìm handle của cửa sổ SAS, SASWindowProc, hàm window procedure của lớp con kế thừa, INJDATA, các dữ liệu đầu vào. Hàm InjectCode int InjectCode () Bỏ qua các chi tiết rườm rà về kỹ thuật (cấp phát bộ nhớ bên tiến trình ở xa, kỹ thuật lấy vùng nhớ ) thì hàm InjectCode làm những động tác sau: o Lấy địa chỉ hàm FindWindowA trong DLL USER32.DLL. o Mở tiến trình winlogon.exe với truy cập toàn quyền. o Sao chép dữ liệu INJDATA với khởi tạo gồm tên lớp "SAS Window class", tên cửa sổ "SAS window", địa chỉ hàm FindWindowA vào tiến trình ở xa. 107
- o Sao chép hàm GetSASWnd vào trong tiến trình ở xa. o Tạo tiểu trình thực hiện việc tìm kiếm handle của cửa sổ SAS. o Nếu thành công, sẽ trả về handle cửa sổ SAS. o Sao chép nội dung hàm SASWndProc vào trong tiến trình ở xa. o Sao chép dữ liệu INJDATA với khởi tạo gồm địa chỉ hàm SetWindowLong (tùy theo tiến trình ở xa có sử dụng Unicode hay không mà sẽ chép tương ứng hàm dạng SetWindowLongA hay SetWindowLongW), CallWindowProc (tùy theo tiến trình ở xa có sử dụng Unicode hay không mà sẽ chép tương ứng hàm dạng CallWindowProcA hay CallWindowProcW), SASWndProc. o Trong SASWndProc, cần sử dụng dữ liệu trong INJDATA nhưng đây là một hàm callback nên tham số đầu vào không thể tùy biến, ta không thể truyền tường minh dữ liệu này. Vì vậy, ở đây, ta đã biết được địa chỉ của dữ liệu đầu vào INJDATA, và cả nội dung hàm SASWndProc đã được ghi vào vùng nhớ bên tiến trình ở xa, ta phải thực hiện động tác ghi trực tiếp giá trị biến nội tại sẽ lưu địa chỉ dữ liệu đầu vào INJDATA, bằng cách tìm trong vùng nhớ ở xa đã ghi nội dung hàm SASWndProc từng DWORD một. Dĩ nhiên biến nội tại này đã lưu một giá trị đặc biệt để có thể tìm ra. o Sao chép nội dung hàm InjectFunc o Tạo tiểu trình thực hiện nội dung hàm InjectFunc: dùng SetWindowLong thay window procedure mới. o Nếu thành công, công việc hoàn tất. Hàm InjectFunc Chức năng: tạo lớp con kế thừa, thay đổi hàm window procedure mới cho cửa sổ SAS. static DWORD WINAPI InjectFunc (INJDATA *pData) Hàm window procedure mới chính là SASWindowProc. Ta không thể lấy dữ liệu từ tiến trình ở xa (ví dụ như truy cập hàm SetWindowLong ) nên mọi dữ liệu đầu vào phải chuẩn bị sẵn và “chích” vào tiến trình, tại đây, lần lượt các hàm sẽ 108
- sử dụng các dữ liệu này. Ở đây, InjectFunc sử dụng địa chỉ hàm SetWindowLong trong INJDATA Ý nghĩa tham số: pData: dữ liệu đầu vào, sẽ được giải thích ở phần sau. Hàm GetSASWnd Chức năng :lấy handle của cửa sổ SAS. static HWND WINAPI GetSASWnd (INJDATA *pData) Hàm SASWindowProc LRESULT CALLBACK SASWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) Nếu đến đây mọi việc “đột nhập” đều suôn sẻ, các công việc sau đây sẽ được thực hiện tiếp trong đoạn mã vừa sao chép (là nội dung các hàm nêu ở trên, các bước sau đều thực hiện trong không gian địa chỉ ảo của tiến trình ở xa): • Lấy handle của cửa sổ SAS : hSASWnd = FindWindow("SAS Window class", "SAS window"); FindWindow là một hàm API khá hữu ích, được dùng để tìm handle của các cửa sổ top-level nếu biết tên cửa sổ và tên lớp. • Tạo lớp con kế thừa window procedure của cửa sổ SAS: SetWindowLong(hSASWnd, GWL_WNDPROC, NewSASWindowProc); • Trong NewSASWindowProc(), bắt thông điệp WM_HOTKEY và trả về 1 cho tổ hợp phím Ctrl – Alt – Del. LRESULT CALLBACK NewSASWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_HOTKEY) { // Ctrl+Alt+Del if (lparam == MAKELONG(MOD_CONTROL | MOD_ALT, VK_DELETE)) return 1; 109
- } return CallWindowProc(OldSASWindowProc, hWnd, wParam, lParam); } Hình 3-9 Màn che mouse và bàn phím 110
- 3.3 Tương tác với hệ thống – Điều khiển danh sách các ứng dụng đang chạy: Trong quá trình thực hiện phần mềm, có một yêu cầu quản trị hệ thống là người quản trị muốn biết tại thời điểm hiện tại, người dùng đang mở những ứng dụng gì. Người quản trị có thể xem danh sách các ứng dụng đó, đồng thời có thể thay đổi bằng cách thêm (mở một ứng dụng mới), bớt (tắt một ứng dụng đang chạy). Yêu cầu này đòi hỏi cần phải tìm hiểu cơ chế quản lý cửa sổ trong hệ điều hành Windows. 3.3.1 Các hàm dạng Enum_ và cơ chế gọi ngược (callback) của Windows: Có một số dữ liệu về hệ thống mà chúng ta khi cần truy cập trực tiếp sẽ rất khó khăn, ví dụ như có bao nhiêu font chữ trên hệ thống ?, có bao nhiêu cửa sổ đang họat động trên hệ thống ? vì các dữ liệu dạng này đều do hệ thống nắm giữ, và hệ thống không muốn chúng ta để ý nhiều về chi tiết quản lý của nó. Do đó, hệ điều hành Windows cung cấp một số các hàm liệt kê sẽ giải đáp những thắc mắc trên của chúng ta. Vấn đề còn lại là hệ thống không biết chúng ta sẽ xử lý như thế nào với những dữ liệu mà nó cung cấp vì dữ liệu dạng này không được tường minh (có thể không có hoặc có rất nhiều), hệ thống phải kiểm tra và trả về từng thành phần dữ liệu một Câu trả lời là hệ điều hành Windows sẽ cung cấp một cơ chế gọi ngược (callback). Nói một cách đơn giản, chúng ta sẽ thông báo với hệ thống rằng khi hệ thống cung cấp các dữ liệu mà ta yêu cầu thì hãy xử lý theo những công việc mà ta đề ra. Hàm mà chứa các công việc ta giao cho hệ thống làm được gọi là hàm gọi ngược (callback function). Một hàm gọi ngược là một hàm do ứng dụng của người dùng tự định nghĩa và được thực thi bởi hệ điều hành mỗi khi có sự kiện liên quan đến hàm xảy ra. 111
- 3.3.2 EnumWindows Để lấy được danh sách các ứng dụng đang chạy, ta sẽ sử dụng cơ chế gọi ngược. Theo cơ chế gọi ngược, hệ điều hành Windows cung cấp một loạt các hàm liệt kê bắt đầu bằng từ Enum (enumerate : liệt kê) như EnumFontFamilliesEx, EnumForms và EnumWindows. EnumWindows chính là hàm ta cần: Hàm EnumWindows Chức năng: liệt kê tất cả cửa sổ top-level trên màn hình bằng cách trả về handle của từng cửa sổ một cho một hàm gọi ngược của ứng dụng định nghĩa. Việc liệt kê sẽ kết thúc khi đến cửa sổ cuối hoặc hàm gọi ngược trả về FALSE. BOOL EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam ); Ý nghĩa tham số: [in] lpEnumFunc : trỏ đến hàm gọi ngược. lParam : giá trị do ứng dụng định nghĩa và chuyển cho hàm gọi ngược. Giá trị trả về: [out] Nếu thành công, trả về khác 0. Nếu thất bại, trả về 0. Để biết lỗi, gọi GetLastError. Định nghĩa hàm gọi ngược của EnumWindows. Chức năng: hàm gọi ngược của EnumWindows. BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam ); Ý nghĩa tham số: 112
- [in] hwnd : handle của top-level windows. lParam : giá trị do ứng dụng định nghĩa và chuyển cho hàm gọi ngược (là tham số lParam trong hàm EnumWindows). Giá trị trả về: [out] Để tiếp tục liệt kê cửa sổ, hàm phải trả về TRUE. Ngược lại, trả về FALSE. Có một lưu ý nhỏ ở đây : ta vẫn có thể sử dụng hàm tương tự là EnumDesktopWindows, là hàm liệt kê tất cả cửa sổ trên desktop. Tuy nhiên, ta có thể lấy thiếu một số cửa sổ người dùng khi sử dụng hàm này. Ngược lại, hàm EnumWindows lại có nhược điểm nhỏ là lấy dư các cửa sổ của hệ thống. Các cửa sổ này không phải là các cửa sổ chúng ta cần, vì vậy ta phải có các thao tác loại bỏ chúng đi. 3.3.3 Lấy danh sách các ứng dụng đang chạy: Ta chỉ cần viết một hàm gọi ngược thực hiện các công việc sau: o Nếu là cửa sổ gọi hàm EnumWindows, bỏ qua. o Nếu là tiểu trình, bỏ qua. o Nếu là cửa sổ ẩn, bỏ qua. o Nếu là cửa sổ không có tiêu đề, bỏ qua. o Nếu là cửa sổ Program Manager, bỏ qua. o Nếu là cửa sổ đang chạy của người dùng (thỏa các điều kiện lọc), lưu lại tên. Hàm ListWindows: Chức năng : hàm gọi ngược thực hiện các công việc trên. BOOL CALLBACK CTaskMgr::ListWindows(HWND hwnd, LPARAM lParam) Ý nghĩa tham số và giá trị trả về: giống mô tả của hàm gọi ngược nêu ở trên. Ở đây, tham số lParam là con trỏ trỏ đến cấu trúc WIN_TEXT_LIST do ta tự định nghĩa để lưu lại tên các ứng dụng: 113
- typedef struct { HWND hWnd; //cua so ma ham CALLBACK thuoc ve CStringArray sarWinText; //array luu window title } WIN_TEXT_LIST; Ý nghĩa cấu trúc khá đơn giản, như đã ghi trong phần chú thích của cấu trúc. Đến đây, mục tiêu để ra đã hoàn tất, ta có thể tùy nghi sử dụng danh sách vào các mục đích khác nhau, như bật và tắt ứng dụng đang chạy. 3.3.4 Tắt một ứng dụng đang chạy: Việc tắt một ứng dụng đang chạy không khó nếu tắt biết rằng ta cần tắt cửa sổ nào. Điều này nghe có vẻ quá hiển nhiên, ta có thể nói rằng “Tôi biết chứ ! Tôi cần tắt cửa sổ này, tên cửa sổ đó là ”, nhưng đối với hệ điều hành Windows tên cửa sổ không có một ý nghĩa gì cả. Điều hệ điều hành cần đó là handle của cửa sổ. Do vậy ta sẽ viết một hàm đóng cửa sổ khi biết tên cửa sổ. Sau đó, mọi việc còn lại quá đơn giản: CWnd* wnd = CWnd::FromHandle(handle); wnd->PostMessage(WM_CLOSE); Ta chỉ làm cửa sổ tự gởi một thông điệp WM_CLOSE cho chính nó. Sau đó, cửa sổ sẽ đóng. Ta không quá lo lắng việc đóng có thành công hay không vì đây thông thường chỉ là các cửa sổ ứng dụng của người dùng, ngoài ra, nếu cửa sổ có chứa dữ liệu mà người dùng chưa lưu (chẳng hạn, ta cần đóng cửa sổ Winword mà người dùng đang gõ văn bản ) hệ điều hành Windows sẽ thông báo hỏi người dùng. Người dùng có thể chọn không đóng cửa sổ. Khi ấy, ta sẽ yêu cầu đóng cửa sổ vào lúc thích hợp khác. Hàm CloseWindow Chức năng: đóng cửa sổ khi biết tên của nó. BOOL CTaskMgr::CloseWindow(LPCTSTR sWinTitle) Hàm CloseWindow sẽ làm các công việc : 114
- o Lấy handle cửa sổ desktop. Cửa sổ này là cửa sổ cha của mọi cửa sổ đang chạy trên màn hình. o Từ cửa sổ desktop, duyệt qua từng cửa sổ con của desktop. o Nếu tìm thấy cửa sổ nào có tên phù hợp với cửa sổ ta cần tìm, đóng nó lại. Hình 3-10 Tắt một ứng dụng đang chạy 3.3.5 Mở một ứng dụng Việc mở một ứng dụng bằng mã lệnh thực thi không khó nếu ta sử dụng đúng hàm API do Windows cung cấp. Ở đây, chỉ có điểm lưu ý nhỏ là ứng dụng chạy nên nêu rõ đường dẫn tuyệt đối. Khi ta sử dụng đường dẫn tương đối, chẳng hạn “control.exe”, hệ điều hành sẽ dò tìm ứng dụng trong: Nơi chứa chương trình ứng dụng Thư mục hiện hành Thư mục system/system32 Thư mục Windows Các thư mục liệt kê trong biến môi trường PATH Vì vậy, có thể ứng dụng không thể được kích hoạt. Hàm ShellExecute: 115
- Chức năng: thực hiện một thao tác (mở, thực thi, tìm kiếm ) một tập tin hay thư mục. HINSTANCE ShellExecute( HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd ); Ý nghĩa tham số: [in] hwnd : handle cửa sổ gọi. lpOperation : thao tác lên tập tin: edit : dùng một trình xử lý văn bản mở tập tin. Nếu lpFile không phải là một tập tin văn bản, thao tác sẽ thất bại. explore : mở thư mục lpFile. find : tìm kiếm trên thư mục lpFile. open : mở tập tin lpFile. lpFile có thể là một tập tin thực thi, văn bản, hay thư mục. print: in tập tin lpFile. Nếu lpFile không phải là một tập tin văn bản, thao tác sẽ thất bại. NULL : Các phiên bản trước Windows 2000: tên thao tác mặc định quy định trong registry. Nếu không, thao tác “open” sẽ được dùng. Các phiên bản từ Windows 2000: tên thao tác mặc định quy định trong registry. Nếu không, thao tác “open” sẽ được dùng. Nếu vẫn không được, hệ điều hành sẽ dùng thao tác đầu tiên đăng ký vào danh sách trong registry. lpFile: tên tập tin hay thư mục. 116
- lpParameters : tham số dành cho lpFile nếu lpFile là một tập tin thực thi. Nếu lpFile là một tập tin văn bản, lpParameters nên đặt là NULL. lpDirectory : đường dẫn tuyệt đối. nShowCmd : SW_HIDE Giấu cửa sổ. SW_MAXIMIZE Phóng to hết cỡ cửa sổ. SW_MINIMIZE Thu nhỏ cửa sổ. SW_RESTORE Phục hồi cửa sổ về kích thước mặc định của nó. SW_SHOW Hiện cửa sổ theo kích thước mặc định của nó. SW_SHOWDEFAULT Đặt trạng thái mặc định của cửa sổ khi mở là hiện ra. SW_SHOWMAXIMIZED Hiện và phóng to hết cỡ cửa sổ. SW_SHOWMINIMIZED Hiện và thu nhỏ cửa sổ. SW_SHOWMINNOACTIVE Thu nhỏ cửa sổ nhưng không kích hoạt nó. SW_SHOWNA Hiện cửa sổ như trạng thái mà nó đã quy định. SW_SHOWNOACTIVATE Hiện cửa sổ nhưng không kích hoạt nó. SW_SHOWNORMAL Hiện và kích hoạt cửa sổ. Giá trị trả về: 117