2010-02-01 3 views
8

Краткая версия: Мне кажется, мне нужна помощь в правильном использовании событий в PowerShell, которые вызывается в результате сообщения Windows, чтобы избавиться от значка всплывающей подсказки.Правильное отображение всплывающей подсказки в лотке в PowerShell

Long Version:

У меня есть команда затянувшийся PowerShell (накопление), что я хотел бы получать уведомления, когда он завершает с помощью баллонной подсказки в системном трее/области уведомлений.

Мне удалось создать скрипт Write-BalloonTip (ниже), который делает примерно то, что я хочу. Единственная проблема заключается в том, что, as sometimes happens with tray icons, значок в трее не исчезает, пока я не курю над ним. Повторно используя одну и ту же глобальную переменную для представления NotifyIcon, я смогу повторно использовать этот скрипт и сохранить его так, чтобы остался только один значок в системном трее (пока я не надвигаюсь на него). Это все еще похоже на хак. Я попытался добавить обработчик событий, чтобы он был уведомлен о событии BalloonTipClosed, а затем удалил его там. В обработчике событий я пробовал все три метода, которые я видел, предлагая избавиться от затянувшегося значка безрезультатно.

Досадной частью является то, что простой .Dispose, похоже, работает с последующими вызовами сценария, что заставляет думать, что блок сценария событий вообще не вызывается.

Я проверил, что BalloonTipClosed вызывается после того, как подсказка исчезает в отдельном приложении WinForms.

Я пропустил что-то основное? Буду признателен за любую оказанную помощь. Благодаря!

Вот код для записи "Write-BalloonTip.ps1":

param 
(
    $text, 
    $title = "", 
    $icon = "Info", 
    $timeout=15000 
) 

[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | out-null 
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | out-null 

if ($global:writeBalloonTipIcon) 
{ 
    # This gets rid of the previous one 
    $global:writeBalloonTipIcon.Dispose() 
} 

$global:writeBalloonTipIcon = new-object System.Windows.Forms.NotifyIcon 
$global:writeBalloonTipIcon.Icon = [System.Drawing.SystemIcons]::Information 

# FIXME: This *should* cleanup the icon after it's done, but it doesn't seem to work 
$global:writeBalloonTipIcon.add_BalloonTipClosed(
    { 
    # this *should* work, but it's not. What am I missing? 
    $global:writeBalloonTipIcon.Icon = $null; 
    $global:writeBalloonTipIcon.Visible = $false; 
    $global:writeBalloonTipIcon.Dispose(); 
    }); 

$global:writeBalloonTipIcon.Visible = $true; 
$global:writeBalloonTipIcon.ShowBalloonTip($timeout, $title, $text, $icon); 
+0

Может быть, немного оффтопик, но я нашел очень полезным Growl для Windows. Jaykul написал библиотеку, которая обертывает функциональность. Существует также плагин, который уведомляет вас о завершении сборки/перестройки. Вы можете найти его здесь: http://huddledmasses.org/more-growl-for-windows-from-powershell/ (я не знаю, является ли это последней версией) – stej

+0

Вы решили? – stej

+0

Не совсем, не было быстрого решения, поэтому мы просто продолжаем утилизировать одну глобальную иконку. Это разумное решение, пока мы не будем мотивированы, чтобы исправить это, обратившись к проблеме STA. –

ответ

2

Я думаю, вам нужно выполнить этот код в потоке STA. PowerShell (v2 показано здесь) выполняется в MTA потоке по умолчанию:

PS U:\> [System.Threading.Thread]::CurrentThread 


ManagedThreadId : 5 
ExecutionContext : System.Threading.ExecutionContext 
Priority   : Normal 
IsAlive   : True 
IsThreadPoolThread : False 
IsBackground  : False 
ThreadState  : Running 
ApartmentState  : MTA 
CurrentUICulture : en-US 
CurrentCulture  : en-US 
Name    : Pipeline Execution Thread 
+0

Я думаю, что это приближается к сути проблемы, так как кажется, что уведомление отправляется через сообщение Windows. Любые идеи о том, как это сделать правильно? Кажется, что Invoke-Apartment должна работать, но я не могу заставить ее работать. –

1

Я бы рекомендовал использовать регистровой ObjectEvent, чтобы подписаться на событие BalloonTipClosed. Это произошло недавно в another SO post. Проверьте это.

+1

Я думаю, что суть проблемы - проблема STA, потому что событие не поднимается, если оно не связано с потоком STA. –

+0

Отчет JIT Debugger сообщает «System.Management.Automation.PSInvalidOperationException: для запуска сценариев в этом потоке нет Runspace. Вы можете указать его в свойстве DefaultRunspace типа System.Management.Automation.Runspaces.Runspace» на BallonTipClosed чтобы событие было поднято. Вы можете сделать Runspace в PS, но значительно быстрее использовать Register-ObjectEvent – Monso

Смежные вопросы