2010-02-01 12 views
8

Versión corta: Creo que necesito ayuda para utilizar correctamente eventos en PowerShell que se invocan como resultado de un mensaje de Windows para eliminar el icono de la información sobre herramientas de globo.Mostrar correctamente una información sobre herramientas de globo en bandeja en PowerShell

Versión larga:

Tengo un sistema de PowerShell de larga duración (acumulación) que me gustaría que se le notifique cuando se completa a través de una información sobre herramientas de globo en el área de la bandeja del sistema/notificación.

Pude crear un script Write-BalloonTip (a continuación) que hace más o menos lo que quiero. El único problema es que, as sometimes happens with tray icons, el ícono de la bandeja no desaparece hasta que muevo el mouse sobre él. Al volver a utilizar la misma variable global para representar el NotifyIcon, puedo volver a utilizar este script y mantenerlo de modo que solo quede un icono de la bandeja del sistema (hasta que lo coloque sobre él). Esto todavía se siente como un truco. Intenté agregar un controlador de eventos para que se notificara en el evento BalloonTipClosed y luego desecharlo allí. En el controlador de eventos, probé las tres técnicas que he sugerido para deshacerme del ícono persistente en vano.

La parte molesta es que un simple .Dispose parece funcionar en las siguientes llamadas al script, lo que me lleva a pensar que el bloque de scripts del evento no se está llamando en absoluto.

He verificado que se llama a BalloonTipClosed después de que la sugerencia se desvanece en una aplicación independiente de WinForms.

¿Me falta algo básico? Cualquier ayuda es muy apreciada. ¡Gracias!

Aquí está el código para "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

Tal vez un poco offtopic, pero me pareció muy útil Growl para Windows. Jaykul escribió una biblioteca que envuelve la funcionalidad. También hay un complemento que le notifica cuando finaliza su construcción/reconstrucción. Puede encontrarlo aquí: http://huddledmasses.org/more-growl-for-windows-from-powershell/ (No sé si es la última versión) – stej

+0

¿Lo ha resuelto? – stej

+0

No realmente, no hubo una solución rápida, así que seguimos reciclando un solo icono global. Es una solución razonable hasta que nos motivemos a solucionarlo manejando el problema STA. –

Respuesta

2

Creo que se necesita para ejecutar este código en un subproceso STA. PowerShell (v2 se muestra aquí) se ejecuta en un subproceso MTA por defecto:

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

Creo que esto se está acercando al núcleo del problema, ya que parece que el evento de notificación se envía a través de un mensaje de Windows. ¿Alguna idea de cómo hacer esto de la manera correcta? Parece que un Invoke-Apartment debería funcionar, pero no puedo hacer que funcione. –

1

yo recomendaría usar el Registro-ObjectEvent para suscribirse al evento BalloonTipClosed. Esto apareció recientemente en another SO post. Echale un vistazo.

+1

Creo que el núcleo del problema es el problema de STA porque el evento no se está levantando a menos que esté en un hilo STA. –

+0

El depurador JIT informa "System.Management.Automation.PSInvalidOperationException: no hay Runspace disponible para ejecutar scripts en este hilo. Puede proporcionar uno en la propiedad DefaultRunspace del tipo System.Management.Automation.Runspaces.Runspace" en el BallonTipClosed evento por lo que el evento se está planteando. Puede hacer un Runspace en PS, pero es mucho más rápido utilizar el Register-ObjectEvent – Monso

Cuestiones relacionadas