Jump to content

Window hook using Python callback + DLL


demberto

Recommended Posts

demberto
Posted (edited)

I was wondering whether, I could do this:

1. Create a DLL with a method to register a callback function written in Python.

2. The DLL calls SetWindowsHookEx internally, registers a proxy function in the DLL itself which calls the Python callback function.

3. Load the DLL in Python with ctypes and call the callback registration method it exports.

I briefly tried this but SetWindowsHookEx fails for global hooks. I see no reason for it to fail. Also according to the documentation I pass NULL for the hMod arg of it which is used when the hook procedure is inside the DLL itself. Maybe I think SetWindowsHookEx will need another injector process which is not a DLL but an application.

So what it will become then is that Python code will load the DLL just for the purpose of executing some code in Python itself. Python -> DLL -> Proxy -> Python that will be the order of execution.

EDIT: I think I posted in wrong section, sorry.

Edited by demberto
Link to comment
demberto
On 5/21/2022 at 8:33 AM, opc0d3 said:

This wouldn't solve your problem ?
https://github.com/ethanhs/pyhooked

Or at least gives you an idea ?

That implements a keyboard hook which doesn't need a DLL. The hook I want to implement needs a DLL. Regardless, I already tried the methods presented there.

On 5/21/2022 at 4:43 PM, Vic said:

You can do it by using pybind11 (https://pybind11.readthedocs.io)

Or python's built-in library

https://docs.python.org/3/extending/extending.html

https://docs.python.org/3/extending/embedding.html

For example, I wrote an app (closed source - temporary personal use only) that can use both C++ DLL & Python code together and flexible.

image.png.7947572c7c7cf886686158538c7401f0.png

image.png.2f5d06ce7bb5480b380329183f1c360a.png

Actually I have managed to do quite some implementation since I posted using raw C (for small DLL size), but it still fails.

I am sure of one thing by now though, SetWindowsHookEx needs to be called from the Python interpreter. It cannot be done from the DLL itself. Which means all my DLL will be is a proxy, it will just store pointers to the real callbacks in Python code. The DLL will export all the hook procedures and a method to register a Python callback as a hook procedure. All this can be neatly exported as a package.

Seems neat enough?

Link to comment
On 5/20/2022 at 3:54 AM, demberto said:

1. Create a DLL with a method to register a callback function written in Python.

2. The DLL calls SetWindowsHookEx internally, registers a proxy function in the DLL itself which calls the Python callback function.

3. Load the DLL in Python with ctypes and call the callback registration method it exports.

Yep. You can put all of them in one DLL. But I give a note for (2) is you must keep it running during hooking. Example:

extern "C" __declspec(dllexport) LRESULT kb_proc(int nCode, WPARAM wParam, LPARAM lParam)
{
  ...
  return CallNextHookEx(nullptr, nCode, wParam, lParam);
}

extern "C" __declspec(dllexport) void hk_register()
{
  const string file_path = "path\\to\\this\\dll";
  auto module = LoadLibraryA(file_path.c_str());

  DWORD tid = 0; // thread id = 0 to hook all threads, otherwise should assign to a specified thread
  SetWindowsHookEx(WH_KEYBOARD, kb_proc, module, tid);

  MessageBoxA(NULL, "Hooking...", "", MB_OK); // <== Example. This message box showing will keep the hook is running (you can use any other way to do this).
}

P.S You can export these functions then call them by Windows API in "win32api, ctypes, etc" python package or write a python wrapper to be able to "import" direct in python code.

Link to comment
demberto
16 hours ago, Vic said:

Yep. You can put all of them in one DLL. But I give a note for (2) is you must keep it running during hooking. Example:

extern "C" __declspec(dllexport) LRESULT kb_proc(int nCode, WPARAM wParam, LPARAM lParam)
{
  ...
  return CallNextHookEx(nullptr, nCode, wParam, lParam);
}

extern "C" __declspec(dllexport) void hk_register()
{
  const string file_path = "path\\to\\this\\dll";
  auto module = LoadLibraryA(file_path.c_str());

  DWORD tid = 0; // thread id = 0 to hook all threads, otherwise should assign to a specified thread
  SetWindowsHookEx(WH_KEYBOARD, kb_proc, module, tid);

  MessageBoxA(NULL, "Hooking...", "", MB_OK); // <== Example. This message box showing will keep the hook is running (you can use any other way to do this).
}

P.S You can export these functions then call them by Windows API in "win32api, ctypes, etc" python package or write a python wrapper to be able to "import" direct in python code.

I tried this it doesn't work for other types of hooks. I tried something new as well, see https://stackoverflow.com/q/72397320

Link to comment
Posted (edited)

 

2 hours ago, demberto said:

doesn't work for other types of hooks

You mean my keyboard hook above works, the others are not?

BTW

1. I see that you did not export functions. Let try to use "extern "C" __declspec(dllexport)" to do it.

2. I also do not see the line whichyou keep the hook running?

Edited by Vic
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...