Monday, November 28, 2011

PowerShell and GTK-Server

Another little five-finger exercise, porting the example VBScript stdin driver to PowerShell. The only annoying thing is that the Start-Process cmdlet doesn't give you direct access to the streams, so we have to drop into .net to fire up the GTK server process.

<#
.SYNOPSIS
demo to use the GTK-server using STDIN.
.DESCRIPTION
This script is based on the VBScript example by
Peter van Eerten published at http://www.gtk-server.org/demo-stdin.vbs.txt
.NOTES
File Name : Try-GTKServer.ps1
Requires : PowerShell Version 1.0
.PARAMETER Help
Show this help text.
#>
param (
[switch] $Help)
if ($help)
{
Get-Help $MyInvocation.MyCommand.Definition
return
}
# hard-coded rather than passed in as a parameter
# I'm feeling lazy tonight...
$gtkpath = "path\to\gtk-server.exe"
## As we want to get at the process stdin, stdout we can't use the Start-Process cmdlet
## $gtkserver = Start-Process -FilePath $gtkpath -ArgumentList "-stdin" -PassThru
## which only allows file I/O
$gtkinfo = new-object System.Diagnostics.ProcessStartInfo @($gtkpath, "-stdin")
$gtkinfo.UseShellExecute = $false
$gtkinfo.RedirectStandardInput = $true
$gtkinfo.RedirectStandardOutput = $true
$gtkinfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
$gtkserver = [System.Diagnostics.Process]::start($gtkinfo)
Function Invoke-GTK
{
Param([string] $command)
$gtkserver.StandardInput.WriteLine($command)
$line = $gtkserver.StandardOutput.ReadLine()
if ($line -cne "ok") { $line }
}
#Define GUI
Invoke-GTK("gtk_init NULL NULL")
$win = Invoke-GTK("gtk_window_new 0")
Invoke-GTK("gtk_window_set_title $win `"PowerShell Script demo program using STDIN`"")
Invoke-GTK("gtk_widget_set_usize $win 450 400")
$table = Invoke-GTK("gtk_table_new 50 50 1")
Invoke-GTK("gtk_container_add $win $table" )
$button = Invoke-GTK("gtk_button_new_with_label Exit")
Invoke-GTK("gtk_table_attach_defaults $table $button 41 49 45 49")
$entry = Invoke-GTK("gtk_entry_new")
Invoke-GTK("gtk_table_attach_defaults $table $entry 1 40 45 49")
$text = Invoke-GTK("gtk_text_new NULL NULL")
Invoke-GTK("gtk_table_attach_defaults $table $text 1 49 8 44")
$radio1 = Invoke-GTK("gtk_radio_button_new_with_label_from_widget NULL Yes")
Invoke-GTK("gtk_table_attach_defaults $table $radio1 1 10 1 4")
$radio2 = Invoke-GTK("gtk_radio_button_new_with_label_from_widget $radio1 No")
Invoke-GTK("gtk_table_attach_defaults $table $radio2 1 10 4 7")
Invoke-GTK("gtk_widget_show_all $win" )
Invoke-GTK("gtk_widget_grab_focus $entry" )
# message/event loop
do {
$event = Invoke-GTK("gtk_server_callback wait")
if ($event -ceq $entry) {
$tmp = Invoke-GTK("gtk_entry_get_text $entry" )
if($tmp.Length -gt 1) {
Invoke-GTK("gtk_text_insert $text NULL NULL NULL `"$tmp`n`" -1")
}
# Empty entry field
Invoke-GTK("gtk_editable_delete_text $entry 0 -1")
}
} while ($event -cne $button)
Invoke-GTK("gtk_server_exit")
view raw gistfile1.ps1 hosted with ❤ by GitHub

Friday, November 18, 2011

Another PowerShell egg-timer (using events)

Recording a learning exercise for how PowerShell handles events, and how to communicate into event handlers

Note that every registered event must be unregistered (otherwise running the script leaves droppings in your PowerShell session in the form of those claims on events). The events that are handled -- the timer 250ms wake-ups -- are consumed by being handled; but the one that is merely waited on remains latched after triggering the wait to release and must be explicitly cleared.

Additional AV frills would be the same as any of the polling loop timer examples out there.

<#
.SYNOPSIS
This script provides simple egg-timer like functionality.
.DESCRIPTION
This script counts down a time interval then speaks some text
.NOTES
File Name : Run-Timer.ps1
Requires : PowerShell Version 2.0
.PARAMETER Minutes
Delay in minutes
.PARAMETER Seconds
Additional delay in seconds
.PARAMETER Text
What to say at the end of the time
.PARAMETER Help
Show this help text.
#>
param (
[ValidateRange(0,59)] [int] $Minutes,
[ValidateRange(0,59)] [int] $Seconds,
[string] $Text="It is time",
[switch] $Help)
if ($help)
{
Get-Help $MyInvocation.MyCommand.Definition
return
}
$delay = new-object "system.timespan" @(0, $Minutes, $Seconds)
$fireAt = [System.DateTime]::UtcNow + $delay
Write-Host "Requested alarm time = `t$fireAt"
# Do the heavy lifting up front
$Voice = new-object -com SAPI.SpVoice
$Voice.Rate = -5
$timer = new-object "system.timers.timer" @(250.0)
$timer.autoreset = $true
$handler = {
# extract arguments (no closures here)
$fireAt = $Event.MessageData
$timer = $Sender
# round time to wait to integer seconds and display
$delta = $fireAt - [System.DateTime]::UtcNow
$delta = new-object "system.timespan" @(0, $delta.Minutes, [System.Math]::Round($delta.Seconds))
[System.Console]::Write("$delta`r")
# After the time allotted, kill the timer
if ([System.DateTime]::UtcNow -gt $fireAt) {
$timer.enabled = $false
$timer.autoreset = $false
$timer.Dispose()
}
}
Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier "Timer.Elapsed" -Action $handler -MessageData $fireAt | Out-Null
Register-ObjectEvent -InputObject $timer -EventName Disposed -SourceIdentifier "Timer.Disposed"
$timer.Start()
# Wait until done
if (-not (Wait-Event "Timer.Disposed" -Timeout 3600 )) {
Write-Host "Timed out"
$timer.Stop()
$timer.Dispose()
} else {
Write-Host "Completed"
}
Write-Host "Actual alarm time = `t$([System.DateTime]::UtcNow)"
# Tidy event registrations and event queue
# The Elapsed events are spent in the handler
# but the one we wait on must be explicitly cleared
Remove-Event "Timer.Disposed"
Unregister-Event "Timer.Elapsed"
Unregister-Event "Timer.Disposed"
#audible alarm
$Voice.Speak($Text) | Out-Null
Write-Host "`r`nDone"
view raw gistfile1.ps1 hosted with ❤ by GitHub


Sunday, November 06, 2011

C# : The null object pattern and the poor man's Maybe Monad

Lots of people have re-invented the Maybe monad in C#, as a simple search will show, usually as a way of bypassing null checking if statements and to be able to write code like

return Music.GetCompany("4ad.com")
.IfNotNull(company => company.GetBand("Pixies"))
.IfNotNull(band => band.GetMember("David"))
.IfNotNull(member => member.Role);
view raw gistfile1.cs hosted with ❤ by GitHub

But we have the tools given to us already if we observe that null has no type -- as we can see when

var x = new string[1]; // default null value
var n = x.OfType<string>().Count();
Console.WriteLine("Length = {0}", n);
view raw gistfile1.cs hosted with ❤ by GitHub

reports a length of zero!

So our Some<T> is just a length-1 IEnumerable<T>; and None<T> an empty one -- the null object pattern, in fact.

For the price of having to specify types at each stage -- as we would anyway have had to in the past for declaring intermediate the values to test against null -- we can use existing methods to finesse the null check. Returning to the borrowed example, it would be

return new[] { Music.GetCompany("4ad.com") }
.OfType<RecordCompany>().Select(company => company.GetBand("Pixies"))
.OfType<Band>().Select(band => band.GetMember("David"))
.OfType<Member>().Select(member => member.Role);
view raw gistfile1.cs hosted with ❤ by GitHub

The monadic return monad extraction operation is just FirstOrDefault(); which is fine for reference types. Value types are different in any case as we wouldn't be null checking those -- as the later steps in a chain though, stopping at the filtering to the value type and making an Any test may be preferred.

Looking at value types, switching to this example, the code looks like:

public static IEnumerable<int> Div(this int numerator, int denominator)
{
//return denominator == 0
// ? Enumerable.Empty<int>()
// : new[] { numerator/denominator };
if (denominator != 0) yield return numerator/denominator;
}
public static IEnumerable<int> DoSomeDivision(int denominator)
{
return from a in 12.Div(denominator)
from b in a.Div(2)
select b;
}
...
var result =
from a in new[] { "Hello World!" }
from b in DoSomeDivision(2)
from c in new[] { new DateTime(2010, 1, 14) }
select (a + " " + b.ToString() + " " + c.ToShortDateString());
Console.WriteLine(result.Any() ? result.First() : "Nothing");
view raw gistfile1.cs hosted with ❤ by GitHub

which leaks a little bit in that we have to do the monadic return monad extraction by hand at the end, but otherwise behaves exactly as the explicit monad implementation.