Giter VIP home page Giter VIP logo

Comments (19)

hhannine avatar hhannine commented on June 12, 2024 1

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.

hhannine avatar hhannine commented on June 12, 2024

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.

hhannine avatar hhannine commented on June 12, 2024

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.

Berserker66 avatar Berserker66 commented on June 12, 2024

The problem is python 3.8 specific though, so something there must have changed and broke it.

from screeninfo.

rr- avatar rr- commented on June 12, 2024

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.

hhannine avatar hhannine commented on June 12, 2024

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.

hhannine avatar hhannine commented on June 12, 2024

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.

rr- avatar rr- commented on June 12, 2024

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.

hhannine avatar hhannine commented on June 12, 2024

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.

rr- avatar rr- commented on June 12, 2024

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.

hhannine avatar hhannine commented on June 12, 2024

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.

rr- avatar rr- commented on June 12, 2024

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.

Berserker66 avatar Berserker66 commented on June 12, 2024

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.

hhannine avatar hhannine commented on June 12, 2024

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.

rr- avatar rr- commented on June 12, 2024

Unfortunately I don't.

from screeninfo.

hhannine avatar hhannine commented on June 12, 2024

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.

rr- avatar rr- commented on June 12, 2024

Merged the fix by @hhannine ; thanks. Would you like me to release the fix now?

from screeninfo.

Berserker66 avatar Berserker66 commented on June 12, 2024

@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.

rr- avatar rr- commented on June 12, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.