Использование Windows Forms Заблокирует сеанс PowerShell ISE через несколько минут после завершения script
У меня здесь интересная проблема. Я создаю календарь для использования, когда мы создаем учетные записи. Он отлично работает и все еще продолжается, но я заметил, что когда я запускаю script в PowerShell ISE, через несколько минут он блокируется (я могу редактировать и сохранять код за несколько минут до этого). В журнале событий ничего нет. Я получаю диалоговое окно, в котором говорится, что powershell не реагирует. Использование памяти также кажется нормальным. Я не знаю, что происходит.
Это происходит независимо от того, как я запускаю PowerShell ISE (Запуск от имени администратора, Запуск от имени другой учетной записи и обычный ISE). Я запускаю Windows 8.1.
Сотрудник предположил, что это модель квартиры, поэтому я пробовал STA и MTA, но проблема возникает в любом случае. Это не происходит, когда один и тот же код запускается с хоста консоли.
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$objForm = New-Object Windows.Forms.Form
$objForm.Text = "Select a Date"
$objForm.Size = New-Object Drawing.Size @(490,250)
$objForm.StartPosition = "CenterScreen"
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({
if ($_.KeyCode -eq "Enter")
{
$script:dtmDate=$objCalendar.SelectionStart
$objForm.Close()
}
})
$objForm.Add_KeyDown({
if ($_.KeyCode -eq "Escape")
{
$objForm.Close()
}
})
$objCalendar = New-Object System.Windows.Forms.MonthCalendar
$objCalendar.Text = "Start"
$objCalendar.ShowTodayCircle = $False
$objCalendar.MaxSelectionCount = 1
$objForm.Controls.Add($objCalendar)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
if ($dtmDate)
{
Write-Host "Date selected: $dtmDate"
}
$objForm.Dispose()
В ответ на @The Unique Paul Smith
function Find-CalenderDateTest {
[CmdletBinding()]
param(
[Parameter(
Mandatory=$false
)]
[ValidateSet('long','short','powerpoint')]
[ValidateNotNullOrEmpty()]
[string]
$DateFormat
)
Begin{
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$objForm = New-Object Windows.Forms.Form
$objForm.Text = "Select a Date"
$objForm.Size = New-Object Drawing.Size @(243,250)
$objForm.StartPosition = "CenterScreen"
$objForm.KeyPreview = $True
$dtmDate = $null
$objForm.Add_KeyDown( {
if ($_.KeyCode -eq "Enter")
{
$dtmDate=$objCalendar.SelectionStart
$objForm.Close()
}
})
$objForm.Add_KeyDown({
if ($_.KeyCode -eq "Escape")
{
$objForm.Close()
}
})
#region OK Button
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(20,175)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
# Got rid of the Click event for OK Button, and instead just assigned its DialogResult property to OK.
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$objForm.Controls.Add($OKButton)
# Setting the form AcceptButton property causes it to automatically intercept the Enter keystroke and
# treat it as clicking the OK button (without having to write your own KeyDown events).
$objForm.AcceptButton = $OKButton
#endregion
#region Cancel Button
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(80,175)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
# Got rid of the Click event for Cancel Button, and instead just assigned its DialogResult property to Cancel.
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$objForm.Controls.Add($CancelButton)
# Setting the form CancelButton property causes it to automatically intercept the Escape keystroke and
# treat it as clicking the OK button (without having to write your own KeyDown events).
$objForm.CancelButton = $CancelButton
#endregion
$objCalendar = New-Object System.Windows.Forms.MonthCalendar
$objCalendar.ShowTodayCircle = $False
$objCalendar.MaxSelectionCount = 1
$objForm.Controls.Add($objCalendar)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
$Results = $objForm.ShowDialog()
}
Process{}
End{
if ($Results -eq "OK")
{
$objCalendar.SelectionStart
}
$objForm.Dispose()
}
}
Ответы
Ответ 1
Я использовал combobox.items.add
:
$configCombo.Items.Add($wks)
и я посмотрел, как сохранить ключи от печати на консоли - и изменил добавление на:
[void]$configCombo.Items.Add($wks)
С тех пор я добавил пустоту - я запускал ее в ISE, и она не видела с тех пор.
Ответ 2
Ошибка MTA/STA
Не используйте
$form.showDialog()
Используйте
[system.windows.forms.application]::run($form)
вместо
и он отлично работает каждый раз
Другой способ - поместить его в другой поток:
$code
{
//form code here
$form.showDialog()
}
$newThread = [Powershell]::Create()
$newThread.AddScript($code)
$handle = $newThread.BeginInvoke()
Предоставить переменные из вызывающего script:
$newThread.Runspace.SessionStateProxy.SetVariable("variablenname",value)
до BeginInvoke
используйте variablenname
без $...
Ответ 3
Это длинный снимок, но проблема может заключаться в том, что powershell не закрывает объект $objForm правильно, оставив его в памяти, в то время как ISE ждет ввода после завершения script. Если вы проверяете свой диспетчер задач, остается ли форма в фоновом режиме? Вы также можете попробовать добавить "Remove-Variable objForm" (нет $) после dispose() и посмотреть, помогает ли это.
Дополнительная информация: https://technet.microsoft.com/en-us/library/ff730962.aspx
Как я уже сказал, это длинный выстрел.
Ответ 4
Иди в эту проблему. Обычно это происходит, когда я блокирую рабочую станцию и возвращаюсь. После того, как я купил и googleing, я нашел это
https://support.microsoft.com/en-us/help/943139/windows-forms-application-freezes-when-system-settings-are-changed-or, что похоже на проблему.
Вопрос
Приложение не будет отвечать, и поток пользовательского интерфейса будет зависать в Вызов вызова при обработке уведомления OnUserPreferenceChanged
Причина
Это происходит, если элемент управления создается на потоке, который не работает сообщения и поток пользовательского интерфейса получает сообщение WM_SETTINGCHANGE.
Разрешение
Приложения никогда не должны оставлять объекты управления в потоках без насос активных сообщений. Если элементы управления не могут быть созданы в основном пользовательском интерфейсе потоки, они должны быть созданы на выделенном вторичном потоке пользовательского интерфейса и Убираются, как только они больше не нужны.