Globalny hook na kolejke komunikatow.

0

Witam,

Otoz mam taki problem. Chcialbym napisac applikacje ktora logowalaby komunikaty z innej aplikacji. Zasada ma byc taka ze aplikacja ta mialaby zalozony hook na systemowa kolejke komunikatow i filtrowala komunikaty ktore ta inna aplikacja wysyla na kolejke komunikatow. Znalazlem funkcje SetWindowsHookEx(...) jednak ta metoda wymaga zeby hook (jako globalny) byl implementowany w oddzielnej dll'ce. Takie rozwiazanie mnie nie urzadza gdyz wtedy ta dll'ka musialaby dalej przekazywac komunikat do aplikacji logujacej.
Czy istnieje inna metoda przechwytywania komunikatow lub zalozenia globalnego hooka?

0

dobra juz sie doczytalem:

Global hooks are not supported in the .NET Framework
Except for the WH_KEYBOARD_LL low-level hook and the WH_MOUSE_LL low-level hook, you cannot implement global hooks in the Microsoft .NET Framework. To install a global hook, a hook must have a native DLL export to inject itself in another process that requires a valid, consistent function to call into. This behavior requires a DLL export. The .NET Framework does not support DLL exports. Managed code has no concept of a consistent value for a function pointer because these function pointers are proxies that are built dynamically.

mozecie to usunac

0
EgonOlsen napisał(a)

Otoz mam taki problem. Chcialbym napisac applikacje ktora logowalaby komunikaty z innej aplikacji.

Sprecyzuj słowo "komunikaty". Z tego co ja zrozumiałem chodzi o jakiś (dowolny) sposób komunikacji między dwiema aplikacjami. Jeśli tak, to nie musisz tego opierać na żadnych globalnych hookach. Wystarczy skorzystać np. z gniazd czy named pipes. I to absolutnie da się zrobić w .NET Framework.

0
Hass napisał(a)
EgonOlsen napisał(a)

Otoz mam taki problem. Chcialbym napisac applikacje ktora logowalaby komunikaty z innej aplikacji.

Sprecyzuj słowo "komunikaty". Z tego co ja zrozumiałem chodzi o jakiś (dowolny) sposób komunikacji między dwiema aplikacjami. Jeśli tak, to nie musisz tego opierać na żadnych globalnych hookach. Wystarczy skorzystać np. z gniazd czy named pipes. I to absolutnie da się zrobić w .NET Framework.

Pipy i gniazda odpadają, to musi być przez PostMessage. Jedna aplikacją ma posyłać komunikaty do drugiej przez PostMessage. Przynajmniej taka była idea. Nie zależy nam w tym momencie na wydajności ale na tym żeby ten message dotarł do drugiej aplikacji nawet kiedy pierwsza padnie na pysk.

A jeśli chodzi o .NET to całe to badziewie nie musi być napisane w .NET może być w czymkolwiek byle nie MFC. ;)

0
EgonOlsen napisał(a)

Pipy i gniazda odpadają, to musi być przez PostMessage. Jedna aplikacją ma posyłać komunikaty do drugiej przez PostMessage. Przynajmniej taka była idea. Nie zależy nam w tym momencie na wydajności ale na tym żeby ten message dotarł do drugiej aplikacji nawet kiedy pierwsza padnie na pysk.

A MSMQ czemu nie może być? Nie jestem w tej dziedzinie ekspertem, ale PostMessage chyba nie jest najlepszym mechanizmem IPC...

0
Hass napisał(a)

A MSMQ czemu nie może być? Nie jestem w tej dziedzinie ekspertem, ale PostMessage chyba nie jest najlepszym mechanizmem IPC...

Problemem nie jest jak to poslac ale jak zalozyc hooka na zdarzenia w innej aplikacji.

0

Da się w .NET założyć globalnego hooka. Tylko jest mały problem z kompatybilnością managed <=> unmanaged i póki co potrafię zastosować tylko obejście, które obniża wydajność.

Nie wiem dlaczego odrzucasz na początku konieczność korzystania z zewnętrznej biblioteki, ale to konieczność, jeżeli chcemy założyć globalny hook, ponieważ ta biblioteka musi być wstrzykiwana.

Tak więc mamy projekt biblioteki:

LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam);

using namespace System;

namespace GlobalMessageHook {

	public ref class Hook
	{
	private:
		Hook() { }
		static Hook^ instance;

	public:
		HHOOK hook;
		property static Hook^ Instance
		{
			Hook^ get()
			{
				if(instance == nullptr)
					instance = gcnew Hook();
				return instance;
			}
		}

		void Initialize()
		{
			hook = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)CallWndProc, NULL, GetCurrentThreadId());
		}

		delegate void NewMessageEventHandler(IntPtr^ hwnd, int message, int lParam, int wParam);

		NewMessageEventHandler^ newMessageEventHandler;

		event NewMessageEventHandler^ OnNewMessage
		{
			void raise(IntPtr^ hwnd, int message, int lParam, int wParam)
			{
				newMessageEventHandler(hwnd, message, lParam, wParam);
			}

			void add(NewMessageEventHandler^ eventHandler)
			{
				newMessageEventHandler += eventHandler;
			}

			void remove(NewMessageEventHandler^ eventHandler)
			{
				newMessageEventHandler -= eventHandler;
			}
		}
	};
}

LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	GlobalMessageHook::Hook^ hook = GlobalMessageHook::Hook::Instance;
	
	if(nCode < 0)
		return CallNextHookEx(hook->hook, nCode, wParam, lParam);

	CWPSTRUCT* messageInfo = (CWPSTRUCT*)lParam;

	hook->OnNewMessage(gcnew IntPtr(messageInfo->hwnd),
		messageInfo->message,
		messageInfo->lParam,
		messageInfo->wParam);

	return CallNextHookEx(hook->hook, nCode, wParam, lParam);
}

Do której możemy dodać sobie referencję gdziekolwiek chcemy i podłączyć się pod event:

Hook.Instance.Initialize();
Hook.Instance.OnNewMessage += new GlobalMessageHook.Hook.NewMessageEventHandler(Instance_OnNewMessage);
Queue<Message> messageQueue = new Queue<Message>();
void Instance_OnNewMessage(ValueType hwnd, int message, int lParam, int wParam)
{
    this.messageQueue.Enqueue(Message.Create((IntPtr)hwnd, message, (IntPtr)lParam, (IntPtr)wParam));
}

I już mówię dlaczego wykorzystałem kolejkę: dowolne odwołanie się do jakiejkolwiek kontrolki Windows Forms kończyło się wyjątkiem naruszenia pamięci. Dlaczego? Nie wiem. Ale już z tej kolejki możemy pobierać komunikaty i robić z nimi co chcemy.

edit: zapomniałem o UnhookWindowsHookEx, ale już idę spać ;).

1 użytkowników online, w tym zalogowanych: 0, gości: 1