moses-palmer / pystray

GNU General Public License v3.0
463 stars 57 forks source link

Importing pystray breaks pywebview #90

Closed simonrob closed 3 years ago

simonrob commented 3 years ago

I've reported this to with a bit more detail as a pywebview issue, but thought it might be worth asking if you had any insight into what could be going on.

I use pystray and pywebview together, and they work with no problems on macOS and Ubuntu. However, on Windows just importing pystray stops pywebview from working – it crashes with OSError : [WinError 1402] Invalid cursor handle as soon as it is started.

Here's a minimal example:

import pystray, webview
window = webview.create_window('Woah dude!', 'https://pywebview.flowrl.com')
webview.start()
moses-palmer commented 3 years ago

Thank you for your report.

Given that merely importing pystray causes the crash, I suppose the cause must lie in the module-global code. I suspect the ctypes argument definitions found in the utility module is the cause.

Do you think that you can try to strip the assignments to argtypes and restype and try again? A prime suspect is RegisterClassEx, as that is sure to be invoked early by any application, and contains an HCURSOR field.

simonrob commented 3 years ago

Thanks for the suggestion. I tried that (i.e., commenting out lines 329 to 331) of win32.py but still encountered the issue. Just to be extra clear: the crash is not on import, but when webview.start() is called.

What does fix the error (and also makes my example from the pywebview issue work is to comment out line 232 of win32.py: DestroyIcon.errcheck = _err (or edit the _err handler).

It turns out that the error handler is being triggered when webview.start() is called, and the parameters at that time are 0, <a _FuncPtr object>, (0,). Because of the result check in the handler, ctypes.WinError() is raised at this point.

I looked at pywebview's source and windll.user32.DestroyIcon is called on window creation here. My knowledge of Win32 is next to nothing, but I wondered whether calling that function on initialisation is normal, or this is just a bug in pywebview. Should it be nested in the if icon_handle != 0: check a few lines above, for example?

If not, is there anything that can be done to mitigate this incompatibility?

moses-palmer commented 3 years ago

Thank you for your research!

The ctypes API is rather problematic since function entrypoints are global resources. pystray makes an attempt at declaring the win32 functions as as they are defined in the documentation, but as this issue demonstrates, if other modules use them differently things may break.

I think the way forward unfortunately will have to be to remove most of the type information from pystray, as this is not the first time third party libraries break because of this. That will require manually checking error codes in this library however.

simonrob commented 3 years ago

I think this crash in particular is actually a bug in pywebview - I submitted a pull request to that project to change the DestroyIcon call to better match the (albeit vague) documentation, so I'm not actually sure it merits changing pysytray's implementation just yet.

However, clearly the underlying Win32 functions don't necessarily behave in the way you might expect - calling DestroyIcon with a null handle hasn't caused any issues for pywebview so far. Maybe it's worth just documenting that there can be problems on Windows if multiple imported packages use these functions, and pointing to the module-global code as a starting point for investigation.

simonrob commented 3 years ago

Just to update: the pull request I submitted has now been merged into pywebview and this particular incompatibility will be fixed from the next version of that library (edit: pywebview version 3.5 now includes this fix). I think this issue can now be closed, though I'll leave it open for now in case you want to use it to track, e.g., documentation updates referencing this type of problem.

Thanks for the help in solving this. (And, of course, for the excellent pystray library!)