Most of the scripts I have written for this blog have custom interfaces for that script. But sometimes you need a Form laid out with the ‘Standard” Windows menu system. This script presents a WinForms Form layout with standard features including a pull-down menu supporting sub-menus, shortcut keys and icons. Also a toolbar with buttons representing menu options and a status bar on the bottom.
 
FormsMenu
 
I first add the .Net assemblies and set EnableVisualStyles. This setting allows the Form to use the colors, fonts and other visual elements that form an operating system theme. All the controls used in the script will utilize the desktop theme.
 

# Install .Net Assemblies
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Enable Visual Styles
[Windows.Forms.Application]::EnableVisualStyles()

 
The below image is FormsMenu running on a desktop with a High Contrast theme so show how the WinForm elements follow the OS desktop theme when setting EnableVisualStyles.
 
FormsMenuHC
 
The objects used in the main form are defined.
 

# Main Form .Net Objects
$mainForm         = New-Object System.Windows.Forms.Form
$menuMain         = New-Object System.Windows.Forms.MenuStrip
$menuFile         = New-Object System.Windows.Forms.ToolStripMenuItem
$menuView         = New-Object System.Windows.Forms.ToolStripMenuItem
$menuTools        = New-Object System.Windows.Forms.ToolStripMenuItem
$menuOpen         = New-Object System.Windows.Forms.ToolStripMenuItem
$menuSave         = New-Object System.Windows.Forms.ToolStripMenuItem
$menuSaveAs       = New-Object System.Windows.Forms.ToolStripMenuItem
$menuFullScr      = New-Object System.Windows.Forms.ToolStripMenuItem
$menuOptions      = New-Object System.Windows.Forms.ToolStripMenuItem
$menuOptions1     = New-Object System.Windows.Forms.ToolStripMenuItem
$menuOptions2     = New-Object System.Windows.Forms.ToolStripMenuItem
$menuExit         = New-Object System.Windows.Forms.ToolStripMenuItem
$menuHelp         = New-Object System.Windows.Forms.ToolStripMenuItem
$menuAbout        = New-Object System.Windows.Forms.ToolStripMenuItem
$mainToolStrip    = New-Object System.Windows.Forms.ToolStrip
$toolStripOpen    = New-Object System.Windows.Forms.ToolStripButton
$toolStripSave    = New-Object System.Windows.Forms.ToolStripButton
$toolStripSaveAs  = New-Object System.Windows.Forms.ToolStripButton
$toolStripFullScr = New-Object System.Windows.Forms.ToolStripButton
$toolStripAbout   = New-Object System.Windows.Forms.ToolStripButton
$toolStripExit    = New-Object System.Windows.Forms.ToolStripButton
$statusStrip      = New-Object System.Windows.Forms.StatusStrip
$statusLabel      = New-Object System.Windows.Forms.ToolStripStatusLabel

 
I use icons on the menu items, main form and the About form. These can acquired in a variety of ways, three of which I used here. First, for the icon on the main form I used the embedded icon from the PowerShell executable calling the System.Drawing.Icon.ExtractAssociatedIcon method.
 

$iconPS   = [Drawing.Icon]::ExtractAssociatedIcon((Get-Command powershell).Path)

 
There are a few icons that can be used in the SystemIcon Class. From this I used the Information icon on the About menu item.
 

[System.Drawing.SystemIcons]::Information

 
The rest of the icons I pull out of shell32.dll, one of many Windows system files which contain icons. Without a direct call from PowerShell, I used the below code comes from the PowerShell Forum in the TechNet Script Center (http://social.technet.microsoft.com/Forums/scriptcenter/en-US/16444c7a-ad61-44a7-8c6f-b8d619381a27/using-icons-in-powershell-scripts?forum=winserverpowershell). After loading the assembly, you have a new Method to extract icons from DLL’s called IconExtractor.
 

# Create Icon Extractor Assembly
$code = @"
using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace System
{
	public class IconExtractor
	{

	 public static Icon Extract(string file, int number, bool largeIcon)
	 {
	  IntPtr large;
	  IntPtr small;
	  ExtractIconEx(file, number, out large, out small, 1);
	  try
	  {
	   return Icon.FromHandle(largeIcon ? large : small);
	  }
	  catch
	  {
	   return null;
	  }

	 }
	 [DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
	 private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);

	}
}
"@
Add-Type -TypeDefinition $code -ReferencedAssemblies System.Drawing

 
I setup the Main Form defining the Menu and Icon and centering in the screen.
 

# Main Form
$mainForm.Height          = 400
$mainForm.Icon            = $iconPS
$mainForm.MainMenuStrip   = $menuMain
$mainForm.Width           = 800
$mainForm.StartPosition   = "CenterScreen"
$mainForm.Text            = " WinForms Menu Demo"
$mainForm.Controls.Add($menuMain)

 
To build the Menu I first add the ToolStrip then the MenuStrip control to the Main Form. ToolsStrip is the base class for MenuStrip and StatusStrip, see the Control Architecture document. I then add the first (Top Level) ToolStripMenuItem, ‘File’, to the Main Menu Items list.
 

# Main ToolStrip
[void]$mainForm.Controls.Add($mainToolStrip)

# Main Menu Bar
[void]$mainForm.Controls.Add($menuMain)

# Menu Options - File
$menuFile.Text = "File"
[void]$menuMain.Items.Add($menuFile)

 
The Drop Down items are then added. The icon is added using the IconExtractor. The numeric is the icon number used to reference it. Shortcut Keys are defined and the text added. The MenuItem is then added as a DropDownItem under the ‘File’ Main menu item.
 

# Menu Options - File / Open
$menuOpen.Image        = [System.IconExtractor]::Extract("shell32.dll", 4, $true)
$menuOpen.ShortcutKeys = "Control, O"
$menuOpen.Text         = "Open"
$menuOpen.Add_Click({OpenFile})
[void]$menuFile.DropDownItems.Add($menuOpen)

# Menu Options - File / Save
$menuSave.Image        = [System.IconExtractor]::Extract("shell32.dll", 36, $true)
$menuSave.ShortcutKeys = "F2"
$menuSave.Text         = "Save"
$menuSave.Add_Click({SaveFile})
[void]$menuFile.DropDownItems.Add($menuSave)

# Menu Options - File / Save As
$menuSaveAs.Image        = [System.IconExtractor]::Extract("shell32.dll", 45, $true)
$menuSaveAs.ShortcutKeys = "Control, S"
$menuSaveAs.Text         = "Save As"
$menuSaveAs.Add_Click({SaveAs})
[void]$menuFile.DropDownItems.Add($menuSaveAs)

# Menu Options - File / Exit
$menuExit.Image        = [System.IconExtractor]::Extract("shell32.dll", 10, $true)
$menuExit.ShortcutKeys = "Control, X"
$menuExit.Text         = "Exit"
$menuExit.Add_Click({$mainForm.Close()})
[void]$menuFile.DropDownItems.Add($menuExit)

 
Nesting a Drop Down Menu Item under another is a matter of just adding it to the upper Drop Down Item, as under ‘Options’.
 

# Menu Options - Tools
$menuTools.Text      = "Tools"
[void]$menuMain.Items.Add($menuTools)

# Menu Options - Tools / Options
$menuOptions.Image     = [System.IconExtractor]::Extract("shell32.dll", 21, $true)
$menuOptions.Text      = "Options"
[void]$menuTools.DropDownItems.Add($menuOptions)

# Menu Options - Tools / Options / Options 1
$menuOptions1.Image     = [System.IconExtractor]::Extract("shell32.dll", 33, $true)
$menuOptions1.Text      = "Options 1"
$menuOptions1.Add_Click({Options1})
[void]$menuOptions.DropDownItems.Add($menuOptions1)

# Menu Options - Tools / Options / Options 2
$menuOptions2.Image     = [System.IconExtractor]::Extract("shell32.dll", 35, $true)
$menuOptions2.Text      = "Options 2"
$menuOptions2.Add_Click({Options2})
[void]$menuOptions.DropDownItems.Add($menuOptions2)

 
The Buttons in the toolbar are made with a ToolStripButton. Each Button uses the icon from the Menu Items and calls the same Functions.
 

# ToolStripButton - Open
$toolStripOpen.ToolTipText  = "Open"
$toolStripOpen.Image = $menuOpen.Image
$toolStripOpen.Add_Click({OpenFile})
[void]$mainToolStrip.Items.Add($toolStripOpen)

 
The Status bar is created by the StatusStrip Class control. The text is created by using a ToolStripStatusLabel Class control.
 

# Status Bar Label
[void]$statusStrip.Items.Add($statusLabel)
$statusLabel.AutoSize  = $true
$statusLabel.Text      = "Ready"
$mainForm.Controls.Add($statusStrip)

 
Most of the Menu Items do nothing, however there are three options with working functions. The first two are “File Open” and “Save As”, which call OpenFileDialog and SaveFileDialog controls. You select what to look for, where to start and what to say. I set a variable with the filename when you make the selection.
 

function OpenFile {
    $statusLabel.Text = "Open File"
    $selectOpenForm = New-Object System.Windows.Forms.OpenFileDialog
    $selectOpenForm.Filter = "All Files (*.*)|*.*"
    $selectOpenForm.InitialDirectory = ".\"
    $selectOpenForm.Title = "Select a File to Open"
    $getKey = $selectOpenForm.ShowDialog()
    If ($getKey -eq "OK") {
        $inputFileName = $selectOpenForm.FileName
    }
    $statusLabel.Text = "Ready"
}

function SaveAs {
    $statusLabel.Text = "Save As"
    $selectSaveAsForm = New-Object System.Windows.Forms.SaveFileDialog
    $selectSaveAsForm.Filter = "All Files (*.*)|*.*"
    $selectSaveAsForm.InitialDirectory = ".\"
    $selectSaveAsForm.Title = "Select a File to Save"
    $getKey = $selectSaveAsForm.ShowDialog()
    If ($getKey -eq "OK") {
        $outputFileName = $selectSaveAsForm.FileName
    }
    $statusLabel.Text = "Ready"
}

 
The final working menu selection is “About”. A new Form is created containing the same PowerShell icon from the main form in a PictureBox as well as a comment.
 
FormsMenuAbout
 

function About {
    $statusLabel.Text = "About"
    # About Form Objects
    $aboutForm          = New-Object System.Windows.Forms.Form
    $aboutFormExit      = New-Object System.Windows.Forms.Button
    $aboutFormImage     = New-Object System.Windows.Forms.PictureBox
    $aboutFormNameLabel = New-Object System.Windows.Forms.Label
    $aboutFormText      = New-Object System.Windows.Forms.Label

    # About Form
    $aboutForm.AcceptButton  = $aboutFormExit
    $aboutForm.CancelButton  = $aboutFormExit
    $aboutForm.ClientSize    = "350, 110"
    $aboutForm.ControlBox    = $false
    $aboutForm.ShowInTaskBar = $false
    $aboutForm.StartPosition = "CenterParent"
    $aboutForm.Text          = "About FormsMenu.ps1"
    $aboutForm.Add_Load($aboutForm_Load)

    # About PictureBox
    $aboutFormImage.Image    = $iconPS.ToBitmap()
    $aboutFormImage.Location = "55, 15"
    $aboutFormImage.Size     = "32, 32"
    $aboutFormImage.SizeMode = "StretchImage"
    $aboutForm.Controls.Add($aboutFormImage)

    # About Name Label
    $aboutFormNameLabel.Font     = New-Object Drawing.Font("Microsoft Sans Serif", 9, [System.Drawing.FontStyle]::Bold)
    $aboutFormNameLabel.Location = "110, 20"
    $aboutFormNameLabel.Size     = "200, 18"
    $aboutFormNameLabel.Text     = "WinForms Menu Demo"
    $aboutForm.Controls.Add($aboutFormNameLabel)

    # About Text Label
    $aboutFormText.Location = "100, 40"
    $aboutFormText.Size     = "300, 30"
    $aboutFormText.Text     = "          Wayne Lindimore `n`r AdminsCache.WordPress.com"
    $aboutForm.Controls.Add($aboutFormText)

    # About Exit Button
    $aboutFormExit.Location = "135, 70"
    $aboutFormExit.Text     = "OK"
    $aboutForm.Controls.Add($aboutFormExit)

    [void]$aboutForm.ShowDialog()
    $statusLabel.Text = "Ready"
} # End About

 
 
Download the complete script here – FormsMenu.ps1

Advertisements