Comments (19)
I wrote a safety that stops trying after 100 queries since they seem to be very fast but I don't quite know what the behavior should be in the running out of retries case. I haven't tested whether dc_full = 0 produces correct resolutions and positions with multiple monitors since I've tested this on my laptop.
I myself am depending on the physical size data to reliably either be present or not but it's not designed for it to come and go. Would be nice if I wouldn't need to implement further workaround down the stream.
from screeninfo.
Same thing here with Python 3.8.2 on Windows 10.
get_monitors() sporadically returns an empty list, sometimes multiple times in succession. No exceptions what so ever.
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[]
>>> get_monitors()
[]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[]
>>> get_monitors()
[]
>>> get_monitors()
[]
>>> get_monitors()
[]
>>> get_monitors()
[]
>>> get_monitors()
[]
>>> get_monitors()
[]
>>> get_monitors()
[]
>>> get_monitors()
[]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')]
>>> get_monitors()
[Monitor(x=0, y=0, width=3200, height=1800, width_mm=310, height_mm=174, name='\\\\.\\DISPLAY1')] >>>
get_monitors()
[]
>>> get_monitors()
[]
from screeninfo.
Small updates:
-
On my Manjaro machine with Python 3.8.1 get_monitors never fails.
-
I digged a bit into this on my Windows machine and found that with the code change:
enum_res = ctypes.windll.user32.EnumDisplayMonitors(
dc_full, None, MonitorEnumProc(callback), 0
)
print("enum_res", enum_res)
print(monitors)
enum_res is 0 when the list is empty so it seems that it is the EnumDisplayMonitors method on Windows that fails. Given that it fails randomly I don't know if we can do anything to it in the scope of screeninfo? I also don't know how to troubleshoot it why it fails since it doesn't throw any errors as is.
from screeninfo.
The problem is python 3.8 specific though, so something there must have changed and broke it.
from screeninfo.
When EnumDisplayMonitors returns a zero value, it means it failed. Could you please try to call WinAPI's GetLastError function and see what error code it returns? (Unfortunately I don't have any code snippets for this) Thanks
from screeninfo.
I installed pypiwin32 to get easier access to GetLastError and by calling it right after EnumDisplayMonitors:
enum_res = ctypes.windll.user32.EnumDisplayMonitors(
dc_full, None, MonitorEnumProc(callback), 0
)
print(GetLastError())
it returns '6' regardless of whether the EnumDisplayMonitors call failed or succeeded.
Edit: Now that I thought it through it should keep printing the last error if the call succeeds..
Edit2: And the error code is something else (126) if the first call in a fresh python instance succeeds.
from screeninfo.
As per here: https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
the code '6' is ERROR_INVALID_HANDLE. I tested printing the dc_full variable during enumeration and it is a negative integer when the call fails and positive when the enumeration succeeds.
from screeninfo.
Out of curiosity, what if you wrap the body of the callback
function with a try: … except Exception as ex: print(ex)
? Maybe it has an unhandled exception and that's what stops the enumeration?
from screeninfo.
Tested with the try catch in the callback and it doesn't catch any exceptions.
I tried replacing the dc_full GetDC call with just a "0" (dc_full = 0) and then the enumeration goes through but it does not get the physical sizes in that case. It seems like that the GetDC method randomly returns an invalid handle.
from screeninfo.
Does changing GetDC(None)
to GetDC(0)
change anything?
Also, I'm not sure, but it's possible we should be calling ReleaseDC
.
If not, our best shot for at least a partial fix I guess is to protect against invalid device contexts by falling back to 0 and not reporting the physical sizes in such cases.
from screeninfo.
Changing GetDC(None) to GetDC(0) didn't seem to change anything. Neither did adding a call to ReleaseDC.
Alternatively maybe we could query for a device context until we get a valid one and then continue to enumeration? The failure rate is not excessively high so this would mean a few extra calls at most.
from screeninfo.
Sounds good, but I'm afraid in pathological cases it could cause the application to hang, so I'd avoid coding a dumb busy loop and add some safety guard (such as if more than 1 s elapsed or we tried more than 100 times, give up)
from screeninfo.
10 tries should be plenty. But it would be nice if that's not necessary at all. Might be some problem with Python 3.8's ctypes? They made changes to the C api calling.
from screeninfo.
Yeah seems like it would be a regression in the GetDC implementation in ctypes or something related. Do you know where we could look for if this is a known issue there or where we should report it?
from screeninfo.
Unfortunately I don't.
from screeninfo.
Finally had access to a Windows machine with 2 monitors to test my changes from here hhannine@2d37a82
Compared to 11/1000 calls failed of the current release my patch does succeed every time. The fall back does not report physical sizes but resolution and x,y positions seems to be OK.
from screeninfo.
Merged the fix by @hhannine ; thanks. Would you like me to release the fix now?
from screeninfo.
@rr-
We're looking at a potential update push next week, the only blocker left for moving to 3.8 in the list is this issue.
(medium size software for German doctor's offices)
from screeninfo.
Thanks for the reply. Released as 0.6.2. Let me know if you still encounter the problem, we'll create a hotfix if needed.
from screeninfo.
Related Issues (20)
- `is_primary` boolean for Monitor objects HOT 2
- conda package for screeninfo HOT 1
- get_monitors returns empty on osx when Enumerator not explicitly provided HOT 1
- WSL
- `y` for a secondary monitor has a different meaning in darwin vs other systems
- customdisplayprofiles current-path not work HOT 2
- Exception: Xinerama is not active HOT 3
- save width and height to a variable HOT 4
- Exception on Raspberry Pi 4 HOT 1
- Ubuntu 22.04: No enumerators available HOT 3
- No enumerations available: Ubuntu 22.04 on X11 HOT 1
- possible GDI Object leak on Windows HOT 3
- Problem with dearpygui
- Add screen diagonal line in inches as an attribute
- Get refresh rate HOT 2
- "No enumerators available" when running in SERVER
- Pull specific values from Monitor X
- Getting No Enumerators Available error when running on pygbag
- No monitor physical dimensions on MacOS HOT 3
- Installation error with conda and python 3.12
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from screeninfo.