Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[user] EnumDisplayDevices result #36

Closed
michidk opened this issue May 23, 2022 · 17 comments
Closed

[user] EnumDisplayDevices result #36

michidk opened this issue May 23, 2022 · 17 comments
Assignees
Labels
bindings Something with the low-level WinAPI bidings bug Something isn't working

Comments

@michidk
Copy link
Contributor

michidk commented May 23, 2022

The EnumDisplayDevices function returns a WinResult. I don't see where Ok(true) is ever set. It also seems like it is not required because we also return a result.

Also, the current example in the docs of that function is a bit weird. The function is supposed to be called until the first error because that means that we finished iterating over all displays:

if !is_finished {

will never be the case, because the ? will return the error.

@rodrigocfd rodrigocfd self-assigned this May 24, 2022
@rodrigocfd
Copy link
Owner

As far as I could investigate, the enumeration ends when EnumDisplayDevices returns zero and GetLastError returns ERROR_PROC_NOT_FOUND, therefore the foolproof implementation has to consider this. The check is necessary to rule out legitimate errors.

I changed the implementation to reflect this. Please let me know if this worked for you.

@rodrigocfd rodrigocfd added enhancement New feature or request bug Something isn't working and removed enhancement New feature or request labels May 24, 2022
@michidk
Copy link
Contributor Author

michidk commented May 24, 2022

Wow that was quick :D. I am not too familiar with winapi error handling stuff, but if I adjusted my code like mentioned in the example:

/// Returns a list of all displays.
pub fn discover_displays() -> Result<DisplaySet> {
    let mut result = Vec::<Display>::new();

    let mut dev_num: u32 = 0;
    let mut display_device = DISPLAY_DEVICE::default();

    loop {
        let has_more = EnumDisplayDevices(
            None,
            dev_num,
            &mut display_device,
            EDD::GET_DEVICE_INTERFACE_NAME,
        )?;

        if has_more {
            result.push(Display::from_winsafe(dev_num, &display_device)?);
            dev_num += 1;
        } else {
            break;
        }
    }

    Ok(DisplaySet { displays: result })
}

Then the fn returns early with the following Err: "[0x00cb 203] The system could not find the environment option that was entered.".

The following works fine:

        let has_more = EnumDisplayDevices(
		...
        ); // no `?`

        if has_more.is_ok() { // `is_ok()` instead
            result.push(Display::from_winsafe(dev_num, &display_device)?);
            dev_num += 1;
        } else {
            break;
        }

This might have to do with the fact that I have one display that is active: false?

@rodrigocfd
Copy link
Owner

rodrigocfd commented May 24, 2022

Indeed, it seems that a display with active: false returns an error for that specific index, and since this is meaningful to you, you'll have to treat that error specifically, and turn the active into some sort of flag. Maybe something like this:

{
	use winsafe as w;

	let mut dev_num: u32 = 0;
	let mut display_device = w::DISPLAY_DEVICE::default();

	loop {
		let (is_good, is_active) = match w::EnumDisplayDevices(
			None,
			dev_num,
			&mut display_device,
			w::co::EDD::GET_DEVICE_INTERFACE_NAME,
		) {
			Ok(r) => (r, true), // active
			Err(e) => match e {
				w::co::ERROR::ENVVAR_NOT_FOUND => (true, false), // inactive
				_ => panic!("Actual error!"),
			}
		};

		if is_good {
			// result.push(Display::from_winsafe(dev_num, &display_device)?);
			println!("{}, active: {}", display_device.DeviceName(), is_active);
			dev_num += 1;
		} else {
			break;
		}
	}
}

@michidk
Copy link
Contributor Author

michidk commented May 24, 2022

When I run your code, I get an infinite loop, because is_good is always true.

But it should stop after there is no display anymore right? I have three active displays and one inactive. This means it should iterate five times, and since the fifth display does not exist an error ("The system could not find the environment option that was entered.") will be thrown and the code should break. This is not the case with the code you just posted.

@rodrigocfd rodrigocfd reopened this May 24, 2022
@michidk
Copy link
Contributor Author

michidk commented May 24, 2022

I only have three displays attached to the four DisplayPort ports on my GPU (maybe the fourth one is also some kind of virtual display output device).
This is how the API calls look in APIMonitor:
image
While all other displays have the active flag there, my fourth "display" shows this flag:
image

@rodrigocfd
Copy link
Owner

This is very unsettling... please run the code below and post back the results:

{
	use winsafe as w;

	for n in 0..8 {
		let mut dide = w::DISPLAY_DEVICE::default();
		let ret = w::EnumDisplayDevices(
			None, n, &mut dide, w::co::EDD::GET_DEVICE_INTERFACE_NAME);
		match ret {
			Ok(b) => println!("{} Ok {}", n, b),
			Err(e) => println!("{} Err {}", n, e),
		}
	}
}

@michidk
Copy link
Contributor Author

michidk commented May 24, 2022

Results in an infinite loop with the following output

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

5 Err [0x00cb 203] The system could not find the environment option that was entered.

6 Err [0x00cb 203] The system could not find the environment option that was entered.

7 Err [0x00cb 203] The system could not find the environment option that was entered.

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

5 Err [0x00cb 203] The system could not find the environment option that was entered.

6 Err [0x00cb 203] The system could not find the environment option that was entered.

7 Err [0x00cb 203] The system could not find the environment option that was entered.

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

5 Err [0x00cb 203] The system could not find the environment option that was entered.

6 Err [0x00cb 203] The system could not find the environment option that was entered.

7 Err [0x00cb 203] The system could not find the environment option that was entered.

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

5 Err [0x00cb 203] The system could not find the environment option that was entered.

6 Err [0x00cb 203] The system could not find the environment option that was entered.

7 Err [0x00cb 203] The system could not find the environment option that was entered.

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

5 Err [0x00cb 203] The system could not find the environment option that was entered.

6 Err [0x00cb 203] The system could not find the environment option that was entered.

7 Err [0x00cb 203] The system could not find the environment option that was entered.

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

5 Err [0x00cb 203] The system could not find the environment option that was entered.

6 Err [0x00cb 203] The system could not find the environment option that was entered.

7 Err [0x00cb 203] The system could not find the environment option that was entered.

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

5 Err [0x00cb 203] The system could not find the environment option that was entered.

6 Err [0x00cb 203] The system could not find the environment option that was entered.

7 Err [0x00cb 203] The system could not find the environment option that was entered.

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

5 Err [0x00cb 203] The system could not find the environment option that was entered.

6 Err [0x00cb 203] The system could not find the environment option that was entered.

7 Err [0x00cb 203] The system could not find the environment option that was entered.

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

5 Err [0x00cb 203] The system could not find the environment option that was entered.

6 Err [0x00cb 203] The system could not find the environment option that was entered.

7 Err [0x00cb 203] The system could not find the environment option that was entered.

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

@rodrigocfd
Copy link
Owner

It's just a for iterating from 0 to 7... it can't be an infinite loop.

Are you running this code inside something else?

@michidk
Copy link
Contributor Author

michidk commented May 24, 2022

Agh sorry. Wanted to get back to you ASAP and got sloppy: I had another loop {} around this from code before. This code actually doesn't loop. Output is just:

0 Ok true
1 Ok true
2 Ok true
3 Ok true
4 Err [0x00cb 203] The system could not find the environment option that was entered.

5 Err [0x00cb 203] The system could not find the environment option that was entered.

6 Err [0x00cb 203] The system could not find the environment option that was entered.

7 Err [0x00cb 203] The system could not find the environment option that was entered.

The code snippet you posted earlier (before the last one) still leads to endless looping.

@rodrigocfd
Copy link
Owner

What about this example in the docs? Does it still loop?

@michidk
Copy link
Contributor Author

michidk commented Jun 1, 2022

No, it does not loop on the latest commit. However, an error is thrown:

0: \\.\DISPLAY1 - NVIDIA GeForce GTX 1080
1: \\.\DISPLAY2 - NVIDIA GeForce GTX 1080
2: \\.\DISPLAY3 - NVIDIA GeForce GTX 1080
3: \\.\DISPLAY4 - NVIDIA GeForce GTX 1080
Error:
   0: [0x00cb 203] The system could not find the environment option that was entered.
   0:

Location:
   src\display.rs:462

The error occurs on the following line:
let is_good = EnumDisplayDevices(None, dev_num, &mut dide, co::EDD::NoValue)?;

@rodrigocfd
Copy link
Owner

This means that when the loop ends, GetLastError returns code 203, which should be the stop condition.

However... on my computer, it returns code 127 instead. That's odd.

I'm on Windows 10 x64, what's yours?

@michidk
Copy link
Contributor Author

michidk commented Jun 1, 2022

Win 10 Pro x64

@rodrigocfd
Copy link
Owner

OK, so I completely removed the internal error checking, and the zero is always considered the "done" state now.

Let me know if this works for you.

@michidk
Copy link
Contributor Author

michidk commented Jun 2, 2022

Output now is:

0: \\.\DISPLAY1 - NVIDIA GeForce GTX 1080
1: \\.\DISPLAY2 - NVIDIA GeForce GTX 1080
2: \\.\DISPLAY3 - NVIDIA GeForce GTX 1080
3: \\.\DISPLAY4 - NVIDIA GeForce GTX 1080

So it works!

We could also handle just 127 as well as 203 as codes for Ok(false).

@rodrigocfd
Copy link
Owner

Yeah, I just did this. This kind of undocumented behavior is really hard to work with.

Thank you very much for your help.

@rodrigocfd rodrigocfd added the bindings Something with the low-level WinAPI bidings label Jan 25, 2023
rodrigocfd added a commit that referenced this issue Aug 10, 2023
@rodrigocfd
Copy link
Owner

@michidk I changed this function to return an iterator, so the loop work is done internally. If you're still interested, I'd be glad to hear if it works for you.

New docs with example can be found here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bindings Something with the low-level WinAPI bidings bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants