2009-06-08 42 views
5

Đã thử một loạt các thứ nhưng tôi không thể làm cho nó hoạt động liên tục giữa thanh tác vụ của tôi bị nuked và các hiệu ứng siêu nhiên khác trên giao diện người dùng trên máy tính để bàn của tôi.Cách thêm hệ thống "móc cửa sổ" để được thông báo về cửa sổ đang được tạo/kích hoạt?

Đã thử sử dụng thư viện mở http://mwinapi.sourceforge.net/ trước tiên. Mặc dù nó hoạt động tốt như một lớp OO để liệt kê các cửa sổ và nội dung. Không thể móc đúng cách

Điểm dừng tiếp theo là Dino E.'s post on Windows Hooks in the .Net framework. Tôi đã kết thúc viết loại của riêng tôi khi tôi đã hiểu được văn bản và cố gắng để có được điều này để làm việc.

Ý định của tôi là chạy ứng dụng này và có thể ghi nhật ký tất cả các cửa sổ đã tạo khi đang chạy. Kêu gọi tất cả nhãn cầu ...

Cập nhật: snipped từ rõ ràng bạn can't write global windows hooks in .Net/mã số quản lý (trừ một số con chuột hoặc bàn phím mức móc thấp)

Vì vậy, tôi chuyển sang C++. Tuy nhiên, tất cả các cuộc gọi WinAPI đều trả về các xử lý hợp lệ nhưng tôi không thấy chức năng lọc của mình đang được gọi - dường như không nhận được bất kỳ thông báo nào. Vẫn không hoạt động ... Ai đó có thể phát hiện ra sai lầm.

void CWinHookFacade::Hook() 
{ 
    HMODULE hCurrentDll = LoadLibrary(_T("[Path to my hook dll]")); 
    m_HookHandle = SetWindowsHookEx(WH_CBT, 
     FilterFunctionForHook, 
     hCurrentDll, 
     0); 
    if (m_HookHandle == NULL) 
    { 
     throw new std::exception("Unable to hook"); 
    } 

} 
void CWinHookFacade::Unhook() 
{ 
    if (!UnhookWindowsHookEx(m_HookHandle)) 
    { 
     throw new std::exception("Unhook failed!"); 
    } 
    m_HookHandle = NULL; 
} 

LRESULT CWinHookFacade::FilterFunctionForHook(int code, WPARAM wParam, LPARAM lParam) 
{ 
    if (code >= 0) 
    { 
     switch(code) 
     { 
     case HCBT_CREATEWND: 
      wprintf(_T("Created Window")); 
      break; 
     case HCBT_ACTIVATE: 
      wprintf(_T("Activated Window")); 
      break; 
     case HCBT_DESTROYWND: 
      wprintf(_T("Destroy Window")); 
      break; 
     } 
    } 

    return CallNextHookEx(m_HookHandle, code, wParam, lParam); 
} 

Khách hàng exe gọi Hook_DLL như thế này

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    CWinHookFacade::Hook(); 
    getchar(); 
    CWinHookFacade::Unhook(); 
} 
+0

Để làm rõ - SetWindowsHookEx trả về một xử lý hợp lệ mỗi lần. Ngoài ra trong trường hợp bất cứ ai muốn thử điều này, mã trên không có bất kỳ phụ thuộc nào khác. Dán vào một tệp .cs trong một dự án trống và chạy. – Gishu

Trả lời

5

Tôi nghĩ rằng những vấn đề bạn đang gặp phải là vì bạn đang cố gắng để thực hiện một chức năng móc trong C#. Dựa trên pinvoke.net's documentation trên SetWindowsHookEx(), nó nói rằng bạn không thể làm điều này - thủ tục móc phải ở trong một DLL không được quản lý. Nếu không, điều này sẽ tải DLL của bạn vào tất cả các tiến trình đang chạy với một vòng lặp thông báo, điều này sẽ làm cho CLR được nạp và bắt đầu trong mỗi quá trình. Điều này không chỉ mất nhiều thời gian, nhưng việc tiêm CLR vào tất cả các quy trình có lẽ không phải là ý tưởng hay nhất. Thêm vào đó, điều gì sẽ xảy ra nếu một tiến trình đã có một CLR đang chạy khác với những gì mà DLL của bạn được xây dựng chống lại?

Cách tiếp cận tốt nhất là di chuyển mã này sang một DLL không được quản lý C++ và sử dụng một số loại giao tiếp liên bộ để gửi dữ liệu bị chặn theo quy trình móc của bạn trở lại ứng dụng của bạn.

Cập nhật

đầu tiên (và điều này có lẽ không gây ra sự cố), tại sao bạn gọi LoadLibrary() để có được những HINSTANCE của DLL của bạn? Nó có lẽ sẽ tốt hơn nếu gọi GetModuleHandle() vì DLL của bạn đã được tải.

Đối với lý do tại sao thủ tục móc của bạn không bao giờ được gọi - bạn đã xác minh điều này như thế nào? Vì bạn đang hooking tất cả các chủ đề GUI trong hệ thống, điều này có nghĩa rằng DLL của bạn cần phải được nạp vào tất cả các quy trình GUI. Có khả năng bạn sẽ không thấy kết quả gọi wprintf() vì các quy trình khác không có cửa sổ bảng điều khiển để hiển thị đầu ra.

Để xác minh rằng tệp DLL của bạn được tải đúng cách, hãy sử dụng chương trình liệt kê các tệp DLL được tải bởi một quy trình (Tôi thích Process Explorer). Bạn có thể sử dụng Tìm kiếm | Tìm mục trình đơn Handle hoặc DLL để tìm kiếm tên của DLL của bạn - nó sẽ hiển thị trong tất cả các tiến trình với một vòng lặp tin nhắn.

Khi bạn đã xác minh rằng DLL của bạn được tải, để xem móc của bạn có được gọi là bạn có thể đính kèm trình gỡ rối vào một tiến trình khác (chẳng hạn như Notepad), và sau đó đặt điểm ngắt trong hàm móc của bạn. Điều đó sẽ biến mất bất cứ khi nào một tin nhắn được gửi đến móc CBT. Nếu bạn không muốn sử dụng trình gỡ lỗi, thì bạn có thể thay đổi các cuộc gọi thành wprintf() thành OutputDebugString() và chạy tiện ích như DebugView để theo dõi kết quả.

Cuối cùng, vì hàm móc của bạn được gọi trong ngữ cảnh của một quá trình khác, biến số m_HookHandle của bạn sẽ không hợp lệ tại đó. Bạn nên lưu trữ nó trong một shared data segment để tất cả các trường hợp đã tải của DLL của bạn sẽ có cùng giá trị.

+0

Tôi biết về phần tiêm - đã có mã của tôi trong một DLL. Nhưng không biết rằng nó không thể làm trong C#. Sẽ thử điều này trong CPP vào ngày mai và đăng nó như thế nào ... Tôi đã bỏ lỡ đọc phần ghi chú trên trang pinvoke để nguy hiểm của tôi. (Tôi thấy rằng ManagedThreadID cũng không hoạt động theo cách khó) – Gishu

+0

Một thứ khác khiến tôi bỏ ra là lớp Hook từ thư viện http://mwinapi.sourceforge.net/ có tham số ctor - bGlobal và được quản lý hoàn toàn. Strange ... – Gishu

+0

Chuyển sang không được quản lý quá - vẫn không có vẻ hoạt động. Cập nhật câu hỏi gốc ... – Gishu

3

Cuối cùng đóng đinh cái này. Hãy viết nó như là một blog post trong trường hợp ai đó cần điều này trong tương lai.

Các vấn đề liên quan