-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Ensure Process.MainWindowHandle is refreshed #32695
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
Conversation
This will set _haveMainWindow to true only if _mainWindowHandle is non-zero. It also forces the latter to be reset during a Process.Refresh() call, hence allowing the re-evaluation of both. Fix dotnet#32690
1586fc3 to
daa5551
Compare
|
Just to mention that, even though all the checks passed, there are a couple of things that could be improved:
|
I was wondering the same thing, but I think it's ok as is. We always return 0 on Unix, even if the process has exited, and since we haven't been throwing for this condition in core until now, I don't see enough value in introducing the exception / breaking change.
This is a holdover from when the Windows code was split to support UWP. What you have is fine, and we should be able to subsequently recombine these Windows files. |
| Assert.Throws<InvalidOperationException>(() => process.MainWindowHandle); | ||
| } | ||
|
|
||
| [Fact(Skip = "Manual test")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't add tests like this; it'll never get run and end up just being dead code.
What prevents writing an automated test that's not permanently disabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only way I can think of to test the full extend of this (i.e. whether MainWindowHandle eventually becomes non-zero) is to spawn a process with a UI. Based on this comment from @danmosemsft, I was assuming that this is undesirable for the pipeline, but it was fine to have a test like that if marked as manual.
However, there is an alternative: rather than checking if MainWindowHandle became non-zero, I could set it to a non-zero value, then check if it was refreshed back to zero. Using reflection, the test could look like this:
[Fact]
[PlatformSpecific(TestPlatforms.Windows)]
public void MainWindowHandle_ShouldRefresh_Windows()
{
FieldInfo handleField = typeof(Process).GetField("_mainWindowHandle", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo flagField = typeof(Process).GetField("_haveMainWindow", BindingFlags.Instance | BindingFlags.NonPublic);
CreateDefaultProcess();
Assert.Equal(IntPtr.Zero, _process.MainWindowHandle);
// MainWindowHandle should not update if _haveMainWindow is true until the process is refreshed
IntPtr fakeHandle = (IntPtr)1234;
handleField.SetValue(_process, fakeHandle);
flagField.SetValue(_process, true);
Assert.Equal(fakeHandle, _process.MainWindowHandle);
_process.Refresh();
Assert.Equal(IntPtr.Zero, _process.MainWindowHandle);
}Instead of using reflection, I could also make use of InternalsVisibleToAttribute (as I see that other libraries do that already), and define the _haveMainWindow and _mainWindowHandle fields as internal. In both cases, the test might be getting too deep into the implementation details. As a slight variant, I could also add an internal setter to MainWindowHandle and an internal property HaveMainWindow, or perhaps an internal method to set those two fields.
Let me know which approach would you prefer and I will update the PR accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be fine if the test is attributed as both [Outerloop] and [Trait(XunitConstants.Category, XunitConstants.IgnoreForCI)]. Then it'll only affect a dev working locally and running outerloop tests, in which case I think popping UI here and there is fair game... we already do it in the Process tests IIRC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, I did the changes as requested. The job "Libraries Test Run release mono OSX x64 Debug" failed, but I would think it is unrelated to the changes, as they should only affect Windows in any case. Is it this same issue perhaps?
stephentoub
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks.
| [PlatformSpecific(TestPlatforms.Windows)] | ||
| public void MainWindowHandle_GetWithGui_ShouldRefresh_Windows() | ||
| { | ||
| const string exePath = "notepad.exe"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: exePath => ExePath
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
Thanks. |
|
Hey @stephentoub, are there any estimates when this fix is planned to be released? |
|
It's checked into master, so barring unforeseen circumstances it'll be part of .NET 5. |
|
@firenero meantime, you can test bits from https://github.com/dotnet/core-sdk (should be there in a few days if not already). We will start releasing official previews of .NET 5 soon. It might not be in the first, but I'd expect it to be in the second. |
|
Thanks! |
|
Also, you could replace any |
|
@fernandreu, Thank you for the workaround. Works like a charm in core 3.1 |
As discussed in #32690, this will set
_haveMainWindowto true only if_mainWindowHandleis non-zero. It also forces the latter to be reset during aProcess.Refresh()call, hence allowing the re-evaluation of both.As suggested, the test I added is marked as manual due to needing to launch a UI (Notepad) as part of it. I did it this using
Fact(Skip = "Manual test")]based on what I saw in ProcessStartInfoTests.StartInfo_WebPage.