2010-02-01 4 views
8

Version abrégée: Je pense avoir besoin d'aide pour utiliser correctement les événements de PowerShell qui sont invoqués suite à un message Windows pour se débarrasser de l'icône d'une info-bulle.Affichage correct d'une info-bulle du bac dans PowerShell

Version longue:

J'ai une commande PowerShell de longue durée (une construction) que je souhaite être averti quand il se termine par une info-bulle de ballon dans la barre d'état système/zone de notification.

J'ai été capable de créer un script Write-BalloonTip (ci-dessous) qui fait à peu près ce que je veux. Le seul problème est que, as sometimes happens with tray icons, l'icône de la barre ne disparaît pas jusqu'à ce que je souris dessus. En réutilisant la même variable globale pour représenter le NotifyIcon, je suis en mesure de réutiliser ce script et de le conserver pour qu'il ne reste qu'une seule icône de la barre d'état système (jusqu'à ce que je la survole). Cela ressemble toujours à un hack. J'ai essayé d'ajouter un gestionnaire d'événement afin qu'il soit notifié sur l'événement BalloonTipClosed et ensuite de l'éliminer. Dans le gestionnaire d'événements, j'ai essayé les trois techniques que j'ai vu suggéré pour se débarrasser de l'icône persistante en vain. La partie ennuyeuse est qu'un simple .Dispose semble fonctionner sur les prochains appels du script, ce qui me laisse penser que le bloc de script d'événement n'est pas appelé du tout.

J'ai vérifié que BalloonTipClosed est appelé après que le conseil s'estompe dans une application WinForms distincte.

Est-ce que je manque quelque chose de basique? Toute aide est très appréciée. Merci!

est ici le code pour "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

Peut-être un peu hors-sujet, mais j'ai trouvé Growl très utile pour Windows. Jaykul a écrit une bibliothèque qui complète la fonctionnalité. Il y a aussi un plugin qui vous avertit lorsque votre build/rebuild se termine. Vous pouvez le trouver ici: http://huddledmasses.org/more-growl-for-windows-from-powershell/ (Je ne sais pas si c'est la dernière version) – stej

+0

L'avez-vous résolu? – stej

+0

Pas vraiment, il n'y avait pas de solution miracle, donc nous continuons à recycler une seule icône globale. Il s'agit d'une solution de contournement raisonnable jusqu'à ce que nous soyons motivés pour résoudre le problème en traitant le problème STA. –

Répondre

2

Je pense que vous devez exécuter ce code dans un thread STA. PowerShell (v2 montré ici) exécute dans un thread MTA par défaut:

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

Je pense que cela se rapproche du cœur du problème car il semble que l'événement de notification est envoyé via un message Windows. Des idées de comment le faire de la bonne façon? Il semble qu'un Invoke-Apartment devrait fonctionner, mais je n'arrive pas à le faire fonctionner. –

1

Je recommanderais d'utiliser le registre-ObjectEvent pour vous abonner à l'événement BalloonTipClosed. Cela est arrivé récemment au another SO post. Vérifiez-le.

+1

Je pense que le noyau du problème est le problème STA parce que l'événement n'est pas soulevé sauf si c'est sur un thread STA. –

+0

Le débogueur JIT signale "System.Management.Automation.PSInvalidOperationException: Il n'y a pas de Runspace disponible pour exécuter des scripts dans ce thread Vous pouvez en fournir un dans la propriété DefaultRunspace du type System.Management.Automation.Runspaces.Runspace" sur le BallonTipClosed événement afin que l'événement est soulevé. Vous pouvez créer un Runspace dans PS, mais il est beaucoup plus rapide d'utiliser Register-ObjectEvent – Monso