Я сталкиваюсь со странным поведением класса Process
при доступе к MainWindowHandle
in. NET Core (3.1).
Рассмотрим следующую функцию:
bool TestProcess()
{
var process = Process.Start("notepad");
try
{
for (var attempt = 0; attempt < 20; ++attempt)
{
process?.Refresh();
if (process?.MainWindowHandle != IntPtr.Zero)
{
return true;
}
Thread.Sleep(100);
}
return false;
}
finally
{
process?.Kill();
}
}
Если функция запускается в. NET Framework, она возвращает true
, как я и ожидал. Однако при использовании. NET Core (3.1 в моем случае) вместо него возвращается false
.
Теперь часть, которая озадачивает меня еще больше:
- Если я установить точку останова в любом месте после запуска процесса, но до того, как будет прочитано свойство
MainWindowHandle
(или, если я просто перейду код хотя бы один раз между этими строками), функция вернет true
. - Если я установите точку останова после чтения свойства
MainWindowHandle
, функция вернет false
. На этом этапе больше не имеет значения, перехожу ли я по коду, устанавливаю больше точек останова и т. Д. c; результат всегда false
.
Что может происходить и как я могу это исправить?
Еще несколько деталей, которые могут или не могут быть быть релевантным:
- Та же проблема может возникнуть с другими процессами, если они имеют GUI (я первоначально обнаружил его с помощью приложения WPF). Вместо этого попробуйте, например,
dfrgui
. - Некоторые процессы, такие как
calc
, по-видимому, порождают отдельный процесс для фактического GUI, поэтому поведение немного меняется: - In. NET Core, функция по-прежнему возвращает
false
, но GUI остается открытым, и трюк с точкой останова больше не работает. - In. NET Framework,
InvalidOperationException
выбрасывается в * Линия 1042 * из-за того, что процесс уже завершился.
- Я использую Visual Studio 2019 (16.4.5), ReSharper 2019.3.2,. NET Core SDK 3.1.101 и Windows 10 (сборка 18363).
- Трюк с точкой останова также работает в Rider (2019.3.3). Однако, только если вы оставляете достаточно времени для отображения главного окна перед возобновлением выполнения программы. Это также может иметь место в Visual Studio, но среда IDE реагирует слишком медленно, чтобы я мог ее протестировать.
Я предполагаю, что отладчик каким-то образом изменяет поведение программы; возможно случайно при перечислении всех свойств процесса, или возможно это связано с потоками, которые он использует. А как именно? Могу ли я повторить такое же поведение?
Некоторые вещи, которые я уже пробовал, но не работали:
- Увеличение количества попыток или времени ожидания между попытками
- Изменение порядка строк
Refresh()
, Thread.Sleep()
и MainWindowHandle
- Замена вызова
Thread.Sleep()
на await Task.Delay()
(и выполнение функции asyn c) - Начать процесс с
UseShellExecute
установлен в true
/ false
явно - Использование
[MTAThread]
или [STAThread]
атрибутов - Печать всех свойств процесса с помощью отражения после его создания / обновления
- Даже если это не сработало, возможно, отладчик считывает эти свойства в другом порядке / порядке, поэтому, возможно, именно поэтому отладка имеет значение.
В качестве предыстории я столкнулся с этой проблемой, когда добавил тесты пользовательского интерфейса в свое приложение WPF с помощью FlaUI (см. проблему, которую я создал ). Теперь я совершенно уверен, что это не проблема самой библиотеки; он просто использует Process.MainWindowHandle
для некоторых своих методов.