Wie einen Mausklick registrieren, wenn das Programm nicht den Fokus hat?
-
Ich schreibe gerade ein kleines Programm (dialogbasierend), welches zwar OnTop läuft, aber nicht den Fokus hat. Es soll auf einen Rechtsklick (irgendwo auf dem Bildschirm) hin die Koordinaten der aktuellen Mausposition in zwei Editfeldern im Programm anzeigen. Wie kann ich nun den "externen" Mausklick abfangen, wenn mein Programm nicht den Fokus hat? Irgendwelche Tips? Danke!
zony
-
Hi!
So einfach ist es leider nicht. Du muss mit Hook's arbeiten.
In deinem Dialog mach folgendes:
in Header:
static HHOOK m_hHook; static HWND m_shWnd; static LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam);
In .cpp:
... HHOOK CHookDialog::m_hHook = NULL; HWND CHookDialog::m_shWnd = NULL; ... // in OnInitDialog(): ... if (m_hHook == NULL) { m_shWnd = GetSafeHwnd(); DWORD dwThreadID = GetCurrentThreadId(); m_hHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, NULL, dwThreadID); } .... // Funktion sieht so aus: LRESULT CALLBACK CDeinDialog::MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if (wParam == WM_RBUTTONUP) { if(m_shWnd) ::SendMessage(m_shWnd, WM_RBUTTONUP, wParam, lParam); } return ::CallNextHookEx(m_hHook, nCode, wParam, lParam); } // Im Destruktor (SEHR WICHTIG !!!): ... if (CDeinDialog::m_hHook) { BOOL bResult = ::UnhookWindowsHookEx(CDeinDialog::m_hHook); CDeinDialog::m_hHook = NULL; } ...
Und, natürlich, muß du die Funktion OnRButtonUp() überladen, wo du deinen Code schreibst.
viel Spaß
-
Danke für deine Hilfe, es funktioniert aber leider bisher noch nicht.
Im Header der CMyToolDlg Klasse (public) habe ich nun folgendes hinzugefügt:
~CMyToolDlg(); static HHOOK m_hHook; static HWND m_shWnd; static LRESULT CALLBACK MouseProc(int, WPARAM, LPARAM); void OnRButtonUp(UINT, CPoint);
In der .CPP Datei habe ich folgendes verändert:
// Direkt nach den Includes HHOOK CMyToolDlg::m_hHook = NULL; HWND CMyToolDlg::m_shWnd = NULL; // Nach dem Konstruktor CMyToolDlg::~CMyToolDlg() { if (CMyToolDlg::m_hHook) { BOOL bResult = ::UnhookWindowsHookEx(CMyToolDlg::m_hHook); CMyToolDlg::m_hHook = NULL; } } // In der OnInitDialog() Funktion BOOL CMyToolDlg::OnInitDialog() { // [...] // TODO: Hier zusätzliche Initialisierung einfügen if (m_hHook == NULL) { m_shWnd = GetSafeHwnd(); DWORD dwThreadID = GetCurrentThreadId(); m_hHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, NULL, dwThreadID); } return TRUE; } // Und am Ende LRESULT CALLBACK CMyToolDlg::MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if (wParam == WM_RBUTTONUP && m_shWnd) ::SendMessage(m_shWnd, WM_RBUTTONUP, wParam, lParam); return ::CallNextHookEx(m_hHook, nCode, wParam, lParam); } void CMyToolDlg::OnRButtonUp(UINT nFlags, CPoint point) { AfxMessageBox(_T("KLICK")); }
Wo liegt mein Fehler?
Das Programm kompiliert ohne Probleme, jedoch erscheint keine Messagebox, wenn ich irgendwo rechtsklicke.
zony
-
Hast du mal einen Breakpoint in der Funktion MouseProc() gesetzt? Läuft sie überhaupt? Wenn ja, versuch andere Maus-Nachrichten abzufangen.
Wie öffnest du deinen Dialog, modal oder nicht modal?
-
Das Programm besteht aus einem einzigen, modalen Dialog. Die MouseProc-Funktion wird nur innerhalb des Programms aufgerufen (nachdem ich das Event ON_WM_RBUTTONUP() hinzugefügt habe). Ich habe inzwischen desöfteren gelesen, dass man die Hooks(?) in eine DLL auslagern muss, damit sie von anderen Applikationen geladen werden können, die dann die Nachricht an meine Applikation schicken. Ich bastle nun seit geraumer Zeit an einer DLL, eine Lösung ist aber noch lange nicht in Sicht...
zony
-
Ja, du hast Recht.
Bei mir läuft der Code in einer Dll.
Ob es bei EXE funktioniert, weiß ich nicht, muss noch ausprobieren...
-
Kannst du mir bei der DLL helfen? Ich habe eine reguläre statisch gegen die MFC gelinkte DLL als Projekt erstellt. Die .CPP der DLL enthält folgendes:
// [...] // Shared Data Segment (in der .def Datei erwähnt unter SECTIONS) #pragma data_seg("MyTool") HHOOK hHook=NULL; HWND hNotifyWnd=NULL; #pragma data_seg() // [...] // Meine MouseProc static LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if (wParam == WM_RBUTTONUP && hNotifyWnd) SendMessage(hNotifyWnd, WM_RBUTTONUP, wParam, lParam); return CallNextHookEx(hHook, nCode, wParam, lParam); } // Funktion zum Starten extern "C" void MonitorMouse(HWND hWnd) { if (hHook) UnhookWindowsHookEx(hHook); hHook = SetWindowsHookEx(WH_MOUSE, MouseProc, NULL, NULL); hNotifyWnd = hWnd; } // Funktion zum Beenden extern "C" void StopMonitorMouse(void) { if (hHook) UnhookWindowsHookEx(hHook); hHook = NULL; }
Und nun die .CPP meines Programms:
// [...] // Funktionszeiger definieren typedef void (*TMonitorMouse) (HWND); typedef void (*TStopMonitorMouse) (); // ... // Destruktor CMyToolDlg::~CMyToolDlg() { // Destruktor if (m_hDLL) { TStopMonitorMouse pStopMonitorMouse = NULL; pStopMonitorMouse = (TStopMonitorMouse) GetProcAddress(m_hDLL, "StopMonitorMouse"); if (pStopMonitorMouse) (*pStopMonitorMouse) (); FreeLibrary(m_hDLL); } } // ... // Message Map BEGIN_MESSAGE_MAP(CMyToolDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_MOUSEMOVE() ON_WM_RBUTTONUP() //}}AFX_MSG_MAP ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST, OnLvnItemchangedList) END_MESSAGE_MAP() // ... // OnInitDialog() BOOL CMyToolDlg::OnInitDialog() { // [...] TMonitorMouse pMonitorMouse = NULL; m_hDLL = LoadLibrary("DLL.dll"); if (m_hDLL) { pMonitorMouse = (TMonitorMouse) GetProcAddress(m_hDLL, "MonitorMouse"); if (pMonitorMouse) (*pMonitorMouse) (GetSafeHwnd()); } else { MessageBox("Unable to load DLL.dll!\nProgram exiting.", "Error", MB_OK|MB_ICONERROR); PostMessage(WM_CLOSE,NULL,NULL); } return TRUE; } // ... // Eventfunktionen void CMyToolDlg::OnRButtonUp(UINT nFlags, CPoint point) { AfxMessageBox(_T("RButtonUp!")); } void CMyToolDlg::OnMouseMove(UINT nFlags, CPoint point) { m_PosX.Format("%d", point.x); m_PosY.Format("%d", point.y); UpdateData(false); }
Es kompiliert mal wieder ohne Fehler, funktioniert aber dennoch nur auf die Oberfläche des Programms selbst beschränkt.
Irgendwelche Tips? Danke!
zony