• Thứ Ba, 23/03/2004 11:04 (GMT+7)

    Câu hỏi :
    Xin hướng dẫn cách liệt kê các cửa sổ trong VC++ giống như khi nhấn Alt+Tab trong Windows.

    Trả lời :

    Bạn có thể dùng các hàm API của Windows là EnumWindows(), EnumDesktopWindows(), EnumChildWindows(),... để duyệt các cửa sổ ứng dụng cũng như những cửa sổ 'con', 'cháu' của chúng. Để giúp bạn hiểu rõ hơn cách gọi các hàm trên để liệt kê các cửa sổ, chúng tôi xin giới thiệu qui trình xây dựng 1 ứng dụng VC++ dạng 'Dialog Based' đơn giản liệt kê các cửa sổ ở mức 'top-level' trên Windows hiện hành:
    1. Chạy VC++, chọn menu File.New để hiển thị cửa sổ 'New', chọn tab 'Project', chọn mục 'MFC AppWizard (exe)', chọn thư mục chứa project ở comboBox 'Location', nhập tên project quản lý ứng dụng cần viết (td. tên là EnumWindows) vào combox 'Project name', chọn button OK rồi trả lời các cửa sổ Wizard để tạo ra project.
    2. Từ form giao diện trống ban đầu (chỉ có 2 button và 1 label), thiết kế giao diện cho form như hình vẽ:
    Nhấn phải chuột trên button, chọn mục Properties để hiển thị cửa sổ thuộc tính của button rồi đặt thuộc tính ID=IDC_REFRESH, Caption='Refresh'. Tương tự với đối tượng listbox, đặt thuộc tính ID=IDC_LIST.
    3. Chọn menu View.ClassWizard để hiển thị cửa sổ ClassWiard, chọn tab 'Member variables', chọn class 'CEnumWindowsDlg' ở listbox 'Class name', chọn mục IDC_LIST trong listbox 'Object IDs', chọn button 'Add Variable' rồi định nghĩa biến m_list kết hợp với đối tượng listbox.
    4. Cũng trong cửa sổ ClassWizard, chọn tab 'Message Map', chọn class 'CEnumWindowsDlg' ở listbox 'Class name', chọn mục IDC_REFRESH trong listbox 'Object IDs', chọn mục BN_CLICKED trong listbox 'Messages' rồi chọn button 'Add Function' để tạo hàm xử lý sự kiện BN_CLICKED của button Refresh với tên mặc định là OnRefresh(). Chọn button 'Edit Code' để viết code của nó như sau:

    // định nghĩa biến tham khảo đến form giao diện
    CEnumWindowsDlg *MyThis;
    // Hàm callback cho hoạt động EnumWindows.
    BOOL CALLBACK CEnumWindowsDlg::EnumWindowsProc (HWND hWnd, LPARAM lParam)
    {
    char lpTitleBar[128];
       // lấy chuỗi titlebar của cửa sổ
       ::GetWindowText(hWnd,lpTitleBar,128);
       // nếu có titlebar thì add nó vào listbox
       if (strlen(lpTitleBar)) 
          MyThis->m_list.AddString(lpTitleBar);
       // tiếp tục duyệt tiếp
       return TRUE;
    }

    // hàm xử lý sự kiện Click button Refresh
    void CEnumWindowsDlg::OnRefresh(){
       // lưu tham khảo đến form vào biến toàn cục
       MyThis = this;
       // xóa nội dung hiện hành trong listbox
       m_list.ResetContent();
       // khởi động quá trình duyệt các cửa sổ top-level
       EnumWindows((WNDENUMPROC)EnumWindowsProc,(LPARAM)NULL);
    }

    Lưu ý trong phát biểu đặc tả class CEnumWindowsDlg (nằm trong file EnumWindowsDlg.h) bạn phải khai báo prototype của hàm EnumWindowsProc() như sau:
    static BOOL CALLBACK CEnumWindowsDlg::EnumWindowsProc (HWND hWnd, LPARAM lParam);
    Nghĩa là hàm EnumWindowsProc() phải là 1 method static của class thì mới có thể đóng vai trò hàm callback (một method bình thường của 1 class không thể là 1 hàm callback).
    5. Chọn menu  Build.Execute EnumWindows để chạy thử ứng dụng, chọn button Refresh để ứng dụng liệt kê và hiển thị các titlebar của các cửa sổ top-level vào listbox. Muốn duyệt các cửa sổ con của 1 cửa sổ bạn có thể dùng hàm API EnumChildWindows(). Bạn có thể liên hệ tòa soạn PCWorld để copy toàn bộ project VC++ (tên là VCEnumWindows) của ứng dụng demo này.

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