本文目录
背景
今天QQ群中CodeCook问了个问题,在PowerShell Studio 2012 工程中创建了一个project,包含了两个窗体,一个主窗体,一个子窗体。在主窗体的按钮单击事件中,启动子窗体。这用c#在vs环境下实现,估计一分钟就够了;在PowerShell ISE下,脚本写得再溜,也得十一二分钟吧。在PowerShell Studio 2012中用一分钟也就够了,这也算体现了PowerShell Studio 2012的价值了。
PowerShell Studio 是什么
PowerShell Studio是一套基于PowerShell的包含脚本编辑,脚本调试,Windows Form设计等功能的集成开发环境(IDE)。其最大的亮点是支持拖拽控件式的Windows Form设计。
PowerShell Studio的调用原理
理解了这个问题,纠结CodeCook的问题自然迎刃而解。
fprojs工程文件
PowerShell Studio的工程文件后缀名为:fprojs 。文件内容自然包含了整个工程的文件清单:
<ProjectState>
  <Version>1.0</Version>
  <FileID>fc295821-bae7-4898-a6c5-bb545f8a1bf4</FileID>
  <OpenFiles>
    <File>Globals.ps1</File>
    <File>Startup.pfs</File>
    <File>MainForm.pff</File>
    <File>child.pff</File>
  </OpenFiles>
</ProjectState>
Globals.ps1文件
Globals.ps1文件为一个原汁原味的PowerShell脚本文件,内面定义一些全局变量或者函数。
Startup.pfs文件
Startup.pfs为工程文件的入口,类似C#中的main函数。默认内容为:
function Main {
	Param ([String]$Commandline)
	if((Call-MainForm_pff) -eq "OK")
	{
	}
	$global:ExitCode = 0 #Set the exit code for the Packager
}
其中关键一行Call-MainForm_pff,用来调用启动主窗体,格式为Call-【窗体名】_pff,这也是本篇博文的灵魂。那也就是意味着在接下的按钮的click事件中我是不是可以这样 Call-ChildForm_pff 调用子窗体,是的,完全正确。
但是CodeCook犯了个小错误,直接F5运行,一直提示有错误。为什么,因为F5是运行当前脚本文件,而这种pff文件是一个伪脚本,不是原汁原味的PowerShell脚本文件,所以报错。应当使用Ctrl+F4运行整个工程。效果如下:
Form.pff文件
那我们再看看pff的文件结构,结构非常清晰,甚至比visual studio自动生成的文件design.cs还清晰(有过之,而无不及),前面使用xml定义控件。
  <Object type="System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="MainForm" children="Controls">
    <Property name="ClientSize">223, 122</Property>
    <Property name="Name">MainForm</Property>
    <Property name="StartPosition">CenterScreen</Property>
    <Property name="Text">Main Form</Property>
    <Event name="Load">OnLoadFormEvent</Event>
    <Object type="System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="btnClickMe" children="Controls">
      <Property name="Location">63, 41</Property>
      <Property name="Name">btnClickMe</Property>
      <Property name="Size">109, 44</Property>
      <Property name="TabIndex">1</Property>
      <Property name="Text">亲爱的,点我呀</Property>
      <Property name="UseVisualStyleBackColor">True</Property>
      <Event name="Click">btnClickMe_Click</Event>
    </Object>
  </Object>
紧接着,利用CDATA定义控件对应的事件:
  <Code><![CDATA[
$OnLoadFormEvent={
#TODO: Initialize Form Controls here
}
$btnClickMe_Click={
	$this.Enabled = $False
	#TODO: Place custom script here
	Call-ChildForm_pff
	#Process the pending messages before enabling the button
	[System.Windows.Forms.Application]::DoEvents()
	$this.Enabled = $True
}
]]></Code>
最后定义引用和版本信息等:
  <Assemblies>
    <Assembly>System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35</Assembly>
    <Assembly>System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</Assembly>
  </Assemblies>
用小学老师作文评语来评价就是:”层次分明,脉络清晰”
导出为一个独立的PowerShell脚本
不管过程怎么花哨,最终得回归到一个Powershell脚本文件,这才是PowerShell Studio的真正归宿。导出后的ps1文件中包含了每个工程文件的名称和源文件的加密数据:
#region Source: Startup.pfs
#region File Recovery Data (DO NOT MODIFY)
<#RecoveryData:
CwcAAB+LCAAAAAAABAC9Vdtu2zAMfR+wf/AHZJY9x0kLqAYCBx2KYVtQF9teFYVOhcqSoUsD//2U
zNfY6YY+BH4xDy+HokQSPwKVr6CqNTEk+fjB8/APxfZMEH7POHwnBSSZIcrY0i9zjdFIe/I5Sj9B
aSZFEvqfMeoDJ4uV1lBsOQN9kjukSrJKGyj8b0SQPRQgjL+yRhbEOOeZV0e5i/zg+M281HJjFdwJ
sEYRPvM21sWlX6F6ki/gDMNtHt3EC7KLFnOIYoxapmnmjmP+vxzb5ZLENF6Et9Ecgpvbf3L4v5jY
yYP276Uq9FUY14ocmNi/hyuI8jhf5mG4iwMSkTe4Ck2l4mx7nRO5N3oVot8Fv86BmAJqpKoyUK+M
wrsextuX1YpN5+ENoS+u0VST1BcQ4ALXYmfQdvcJRJNoDT7Qus0HpkPUtTfLQZtUwamzkxCjEdZa
p1a7EdDoe7EvKTacmNz1VvLJxW2FVv1oRfa0SgKM6r/OUR5AZc/AeTOv3Pgag3Wx0LBaOANqFTOV
hxpk6HA2G7tzTKIbJXeWmrH1JUWNn1/VFLoGTRUrh2VGk2gqi5KIql/1cySVZeU2wfPgasbYgzCg
3LY4S3Aanlwtfx0uq1xmx5UxzLWHYDRYQ6j3+t1b6C+/P5RBcLgLBwAA#>
#endregion
#----------------------------------------------
#region Import Assemblies
#----------------------------------------------
[void][Reflection.Assembly]::Load("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][Reflection.Assembly]::Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][Reflection.Assembly]::Load("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
[void][Reflection.Assembly]::Load("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][Reflection.Assembly]::Load("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][Reflection.Assembly]::Load("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][Reflection.Assembly]::Load("System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
#endregion Import Assemblies
我们看看之前提到的Call-ChildForm_pff变成什么样子了,贴出一段,这下很眼熟了吧。
#---------------------------------------------- #region Generated Form Objects #---------------------------------------------- [System.Windows.Forms.Application]::EnableVisualStyles() $formChildForm = New-Object 'System.Windows.Forms.Form' $InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState' #endregion Generated Form Objects #…… #region Generated Form Code #---------------------------------------------- # # formChildForm # $formChildForm.ClientSize = '249, 109' $formChildForm.Name = "formChildForm" $formChildForm.Text = "Child Form" $formChildForm.add_Load($formChildForm_Load) #endregion Generated Form Code #---------------------------------------------- #Save the initial state of the form $InitialFormWindowState = $formChildForm.WindowState #Init the OnLoad event to correct the initial state of the form $formChildForm.add_Load($Form_StateCorrection_Load) #Clean up the control events $formChildForm.add_FormClosed($Form_Cleanup_FormClosed) #Store the control values when form is closing $formChildForm.add_Closing($Form_StoreValues_Closing) #Show the Form return $formChildForm.ShowDialog()
写作最后
PowerShell Studio像PowerShell一样,其方便成就了其强大,可以用来做一些小的Windows窗体工具。但是考虑到PowerShell解释性语言的性能,你会用它做软件吗?反正我是不会。
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!



哇,我出名了诶!
所以,还要感谢你啦。