• Thứ Tư, 17/05/2006 09:41 (GMT+7)

    Bắt sự kiện "Ctrl-C" trong VB.NET

    Câu hỏi :
    Xin hướng dẫn tạo 1 chương trình VB .Net chạy nền nhận biết phím ấn của người dùng, ví dụ “Ctrl-C”. Trên CD MSDN April 2005 có các bài viết về cách Hook bàn phím nhưng chỉ đề cập đến VC++ còn VB .Net thì không có.


    Trả lời :

    Để các hàm Hook của bạn có tác dụng ở cấp độ hệ thống (luôn tác dụng bất chấp ứng dụng hay cửa sổ hiện hành nào đang hoạt động), bạn nên đặt các hàm hook này trong thư viện liên kết động *.dll. Mặc dù bạn có thể dùng nhiều ngôn ngữ khác nhau để viết thư viện *.dll, nhưng ngôn ngữ C++ là thích hợp hơn cả, rồi từ chương trình (thí dụ viết bằng VB .Net), bạn có thể gọi các hàm thư viện để thực hiện chức năng hook tương ứng. Thí dụ để tạo thư viện *.dll chứa 2 hàm KeyboardHook() và KeyboardUnhook() bằng VC++, bạn có thể tiến hành các bước sau:

    1. chạy VC++, chọn menu File.New.Project, chọn mục Win32 Dynamic-link Library, chọn vị trí thư mục chứa project, nhập tên project quản lý thư viện (thí dụ như KeyboardHook). Khi cửa sổ Wizard - Step 1 hiển thị, bạn chọn checkbox A DLL that export any symbols và chọn button Finish để hoàn tất qui trình Wizard.

    2. chọn tab File View trong cửa sổ hiển thị cây Project, mở rộng mục Header Files, ấn kép chuột vào file KeyboardHook.h để hiển thị nội dung của file này. Hiệu chỉnh lại nội dung file để chứa các prototype sử dụng của các hàm mà bạn muốn thư viện cung cấp cho ứng dụng. Thí dụ để miêu tả thư viện có 2 hàm KeyboardHook() và KeyboardUnhook(), nội dung của file sẽ là:
    #ifdef KEYBOARDHOOK_EXPORTS
    #define KEYBOARDHOOK_API __declspec(dllexport)
    #else
    #define KEYBOARDHOOK_API __declspec(dllimport)
    #endif
    //Prototype của các hàm thư viện
    KEYBOARDHOOK_API int KeyboardHook(void);
    KEYBOARDHOOK_API int KeyboardUnHook(void);

    3. chọn menu File.New.Files để tạo file định nghĩa đặc tả thư viện KeyboardHook.def. Thí dụ để miêu tả thư viện có 2 hàm KeyboardHook() và KeyboardUnhook(), nội dung của file KeyboardHook.def sẽ là:
    LIBRARY   KeyboardHook
    HEAPSIZE  8192
    STACKSIZE 8192
    EXPORTS
     KeyboardHook   @1
     KeyboardUnHook @2

    4. tiếp tục mở rộng mục Source Files trong cửa sổ miêu tả cây Project, nhấn đúp chuột vào file KeyboardHook.cpp và hiện thực các hàm đã khai báo trong file KeyboardHook.h. Thí dụ để hook bàn phím chặn trình tự phím Ctrl-C, bạn có thể viết code cho file KeyboardHook.cpp như sau:
    #include "stdafx.h"
    #include "KeyboardHook.h"
    //định nghĩa các biến cần dùng
    BYTE fHookKeyboard = 0;
    HHOOK hHookKeyboard=(HHOOK)NULL;
    HINSTANCE hModuleDll=(HINSTANCE)NULL;
    //định nghĩa hàm khởi động/dừng thư viện
    BOOL APIENTRY DllMain(HANDLE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved) {
       switch (ul_reason_for_call) {
       case DLL_PROCESS_ATTACH:
       case DLL_THREAD_ATTACH:
          if (hModuleDll==0)  hModuleDll= (HINSTANCE)hModule;
          break;
       case DLL_THREAD_DETACH:
       case DLL_PROCESS_DETACH:
          break;
       }
       return TRUE;
    }

    //định nghĩa hàm xử lý sự kiện chuột theo yêu cầu
    LRESULT FAR PASCAL CALLBACK KeyboardProc (int nCode, WPARAM wParam, LPARAM lParam) {
    short FAlt, FControl, FShift;
       if (nCode >= 0 && nCode != HC_NOREMOVE && lParam >0) {
          //xác định trạng thái nhấn các phím điều khiển
          FShift = GetKeyState(VK_SHIFT);
          FAlt = GetKeyState(VK_MENU);
          FControl = GetKeyState(VK_CONTROL);
     if (FControl < 0 && wParam == 'C') {
             //xử lý sự kiện ấn Ctrl-C theo yêu cầu
             //ở đây chúng tôi chỉ hiển thị hộp thoại thông báo
             MessageBox(NULL,"Bạn vừa ấn Ctrl-C","Thu vien KeyboardHook",MB_OK);
             return CallNextHookEx(hHookKeyboard, nCode, wParam, lParam);
          }
       }
       //gọi hàm xử lý sự kiện chuột của Windows
       return CallNextHookEx(hHookKeyboard, nCode, wParam, lParam);
    }

    //Hàm thiết lập hook sự kiện bàn phím.
    //nếu thành công trả về 1, nếu thất bại trả về 0
    KEYBOARDHOOK_API int KeyboardHook(void) {
       if (fHookKeyboard) return 1;
       hHookKeyboard = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,
     hModuleDll, 0);
       if (hHookKeyboard == NULL) return 0;
       fHookKeyboard = 1;
       return 1;
    }

    //Hàm gỡ bỏ hook sự kiện bàn phím.
    //nếu thành công trả về 1, nếu thất bại trả về 0
    KEYBOARDHOOK_API int KeyboardUnHook(void) {
       if (fHookKeyboard==0) return 0;
       fHookKeyboard = 0;
       return UnhookWindowsHookEx(hHookKeyboard);
    }

    5. Dịch và tạo file thư viện KeyboardHook.dll, nếu có lỗi thì sửa cho đến khi hết lỗi. Copy file thư viện KeyboardHook.dll vào thư mục quản lý (thí dụ c:\MyDll\).

    6. Chạy Visual Studio .Net, tạo project VB .Net để quản lý ứng dụng, thí dụ dạng "Windows Application" là dạng ứng dụng có 1 form giao diện ban đầu. Tạo 2 button tên là btnHook và btnUnHook để kiểm tra (và dùng thử) thư viện vừa xây dựng ở các bước trên. Để gọi được các hàm thư viện, bạn phải dùng lệnh Declare để khai báo các hàm này trong module tương ứng, thí dụ như sau:
    'khai báo các hàm KeyboardHook & KeyboardUnHook
    Private Declare Function KeyboardHook Lib "c:\MyDll\KeyboardHook.dll" () As Long
    Private Declare Function KeyboardUn
    Hook Lib "c:\MyDll\KeyboardHook.dll" () As Long
    'Hàm xử lý sự kiện click trên button Hook
    Private Sub btnHook_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHook.Click
       KeyboardHook()
    End Sub
    'Hàm xử lý sự kiện click trên button UnHook
    Private Sub btnUnHook_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUnHook.Click
       KeyboardUnHook()
    End Sub

    7. Chạy thử ứng dụng và kiểm tra kết quả, nếu mọi việc diễn tiến đúng như các bước trên thì khi bạn ấn button Hook, ứng dụng sẽ hook sự kiện bàn phím, nghĩa là mỗi lần bạn tác động trên phím ấn thì máy sẽ gọi hàm xử lý KeyboardProc() trong thư viện của bạn. Từ đây trở đi, mỗi lần bạn ấn Ctrl-C, máy sẽ hiển thị 1 hộp thoại thông báo (bạn sẽ hiệu chỉnh lại đoạn code xử lý này theo yêu cầu riêng) cho đến khi bạn ấn button UnHook, ứng dụng sẽ gỡ bỏ hook bàn phím của bạn ra. Từ đây mỗi khi bạn ấn Ctrl-C, máy sẽ không gọi hàm KeyboardProc() trong thư viện của bạn nữa.

    Chuyên mục: Lập trình