2010-02-01 11 views
8

Kurzversion: Ich denke, ich brauche Hilfe bei der korrekten Verwendung von Ereignissen in PowerShell, die als Ergebnis einer Windows-Meldung aufgerufen werden, um das Icon eines Balloon Tooltips zu entfernen.Korrektes Anzeigen eines Taskleistensymbols in PowerShell

Long Version:

Ich habe einen lang andauernde Powershell-Befehl (ein Build), dass ich benachrichtigt werden möchte, wenn es über einen Ballon Tooltip in der Taskleiste/Infobereich vervollständigt.

Ich konnte ein Write-BalloonTip-Skript (unten) erstellen, das ungefähr das tut, was ich will. Das einzige Problem ist, dass, as sometimes happens with tray icons, das Tray-Icon nicht verschwindet, bis ich die Maus darüber. Indem ich die gleiche globale Variable wiederverwende, um die NotifyIcon darzustellen, kann ich dieses Skript wiederverwenden und es so behalten, dass nur noch ein Taskleistensymbol übrig bleibt (bis ich die Maus darüber bewege). Das fühlt sich immer noch an wie ein Hack. Ich habe versucht, einen Event-Handler hinzuzufügen, damit er über das Ereignis BalloonTipClosed benachrichtigt wird und ihn dann dort ablegt. Im Event-Handler habe ich alle drei vorgeschlagenen Techniken ausprobiert, um das veraltete Icon loszuwerden, ohne Erfolg.

Der ärgerliche Teil ist, dass eine einfache .Dispose scheint bei nachfolgenden Aufrufen des Skripts zu arbeiten, führt mich zu der Annahme, dass der Ereignis Skriptblock überhaupt nicht aufgerufen wird.

Ich habe überprüft, dass BalloonTipClosed aufgerufen wird, nachdem der Tipp in einer separaten WinForms-App ausgeblendet wird.

Fehle ich etwas Grundlegendes? Jede Hilfe wird sehr geschätzt. Vielen Dank!

Hier ist der Code für "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

Vielleicht ein wenig offtopic, aber ich fand sehr nützlich Knurren für Windows. Jaykul schrieb eine Bibliothek, die die Funktionalität umschließt. Es gibt auch ein Plugin, das Sie benachrichtigt, wenn Ihr Build/Wiederaufbau abgeschlossen ist. Sie können es hier finden: http://huddledmasses.org/more-growl-for-windows-from-powershell/ (Ich weiß nicht, ob es die neueste Version ist) – stej

+0

Haben Sie es gelöst? – stej

+0

Nicht wirklich, es gab keine schnelle Lösung, also recyceln wir nur ein einziges globales Symbol. Es ist eine sinnvolle Problemumgehung, bis wir motiviert werden, es tatsächlich zu beheben, indem Sie das STA-Problem behandeln. –

Antwort

2

Ich glaube, Sie müssen diesen Code in einem STA-Thread auszuführen. Powershell (v2 hier gezeigt) führt in einem MTA-Thread standardmäßig:

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

Ich denke, dies nähert sich dem Kern des Problems, da es scheint, dass das Benachrichtigungsereignis über eine Windows-Nachricht gesendet wird. Irgendwelche Ideen, wie man das richtig macht? Es scheint, dass ein Invoke-Apartment funktionieren sollte, aber ich kann es nicht richtig zum Laufen bringen. –

1

Ich würde empfehlen, den Register-Object mit zum BalloonTipClosed Ereignisse abonnieren. Dies kam kürzlich in another SO post. Hör zu.

+1

Ich denke, der Kern des Problems ist das STA-Problem, da das Ereignis nicht ausgelöst wird, es sei denn, es ist in einem STA-Thread. –

+0

Der JIT-Debugger meldet "System.Management.Automation.PSInvalidOperationException: In diesem Thread ist kein Runspace zum Ausführen von Scripts verfügbar. Sie können ihn in der DefaultRunspace-Eigenschaft des System.Management.Automation.Runspaces.Runspace-Typs auf dem BallonTipClosed angeben Ereignis, so dass die Veranstaltung ausgelöst wird. Sie können einen Runspace in PS erstellen, aber es ist wesentlich schneller, das Register-ObjectEvent zu verwenden – Monso