超赞的Visual Studio命令提示符和PowerShell图标覆盖


[原文发表地址]Awesome Visual Studio Command Prompt and PowerShell icons with Overlays

[原文发表时间]2010-08-18 17:00

一般来说,我并不属于“图标一族”。我的意思是说,我并没有收集图标,或者把系统上的图标换成自定义炫酷图标。不过,今天我注意到自己在使用Visual Studio 命令提示符(拥有正确路径和环境设置的命令提示符),还有常规PowerShell,以及PowerShell“VSVars32”设置提示符(再重申一下,就是有正确环境设置的PowerShell)。他们的图标都不尽相同。

看来是个恰好的机会来编辑一些新的图标,改变一下我的世界了。搜索,并下载了我所知道的最有趣的免费图标编辑器,叫做IcoFX。我鼓励你们去资助他们,因为他们在全世界范围内提供了一个很棒的服务。我在cmd.exe,devenv.exe和powershell.exe上用过他们的提取命令。

clip_image001

免责声明:我想我这么做的确触犯了各种国际条例或者其他规定。当Ninjas跑进来说“你不能用我们的图标来取乐。”的时候,我会否认写过这篇博文。请支持我。我只是自寻其乐而已。并不是微软什么的官方产品,你也不能说这是官方的。你是谁!?不要再说我了。Jimmy不在这儿。别再打来了。

另外:这是我还未触及的部分。看上去VS2010图标编辑器在alpha通道部分仍然有问题。其实我一直对整个产品感到反感,不过既然我不是那个团队中的一员,我就得花功夫去深究一些细节问题了。我倒是希望在VS中把这些全解决掉。

好了,现在我把所有的图标都加载到了IcoFX。我会把它们都编辑一下,并在所有可获方案中做出最优的图标,尽管从技术上来说我的Windows 7任务栏和桌面只需要32x32的图标。

clip_image002

稍稍编辑和调整大小。说真的,这个图标编辑器 真的是一种享受。开始做吧!

clip_image003

我把这些保存为vscommand.ico和vspowershell.ico,现在,我桌面上就有这两个很好看的图标了。

clip_image004

我把“Visual Studio命令提示符”贴到任务栏上,如下图所示:

clip_image005

我还给系统菜单做了一个小的图标,因为这是我的一贯做法。

clip_image006

好了,多棒啊。

不过,在PowerShell中,我有时候会通过运行添加在Microsoft.PowerShell_profile.ps1中的自定义PowerShell VSVars脚本来转换我的VSVars。还记得Chris Tavares里的这个脚本吗?

   1: function Get-Batchfile ($file) {
   2:     $cmd = "`"$file`" & set"
   3:     cmd /c $cmd | Foreach-Object {
   4:         $p, $v = $_.split('=')
   5:         Set-Item -path env:$p -value $v
   6:     }
   7: }
   8:   
   9: function VsVars32($version = "10.0")
  10: {
  11:     $key = "HKLM:SOFTWARE\Microsoft\VisualStudio\" + $version
  12:     $VsKey = get-ItemProperty $key
  13:     $VsInstallPath = [System.IO.Path]::GetDirectoryName($VsKey.InstallDir)
  14:     $VsToolsDir = [System.IO.Path]::GetDirectoryName($VsInstallPath)
  15:     $VsToolsDir = [System.IO.Path]::Combine($VsToolsDir, "Tools")
  16:     $BatchFile = [System.IO.Path]::Combine($VsToolsDir, "vsvars32.bat")
  17:     Get-Batchfile $BatchFile
  18:     [System.Console]::Title = "Visual Studio " + $version + " Windows Powershell"
  19:     //add a call to set-consoleicon as seen below...hm...!
  20: }

为什么不断然处之,和Aaron Lerch’s为“改变Windows PowerShell控制台图标”而写的脚本合并起来呢?这样的话,当我调用“vsvars32”时,我会同时改变我PowerShell的图标。

以下是Aaron的脚本,做过一些变更,使其成为点源函数,还进行了一些修改。这能快速改变系统菜单图标,不过不会更新任务栏或者ALT-TAB。我也不确定这能否实现。

   1: ##############################################################################
   2: ## Script: Set-ConsoleIcon.ps1
   3: ## By: Aaron Lerch, tiny tiny mods by Hanselman
   4: ## Website: www.aaronlerch.com/blog 
   5: ## Set the icon of the current console window to the specified icon
   6: ## Dot-Source first, like . .\set-consoleicon.ps1
   7: ## Usage:  Set-ConsoleIcon [string]
   8: ## PS:1 > Set-ConsoleIcon "C:\Icons\special_powershell_icon.ico" 
   9: ##############################################################################
  10:  
  11: $WM_SETICON = 0x80
  12: $ICON_SMALL = 0
  13:  
  14: function Set-ConsoleIcon
  15: {
  16:     param(
  17:         [string] $iconFile
  18:     )
  19:  
  20:     [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | out-null
  21: $iconFile
  22:     # Verify the file exists
  23:     if ([System.IO.File]::Exists($iconFile) -eq $TRUE)
  24:     {
  25:         $icon = new-object System.Drawing.Icon($iconFile) 
  26:  
  27:         if ($icon -ne $null)
  28:         {
  29:             $consoleHandle = GetConsoleWindow
  30:             SendMessage $consoleHandle $WM_SETICON $ICON_SMALL $icon.Handle 
  31:         }
  32:     }
  33:     else
  34:     {
  35:         Write-Host "Icon file not found"
  36:     }
  37: }
  38:  
  39:  
  40: ## Invoke a Win32 P/Invoke call.
  41: ## From: Lee Holmes
  42: ## http://www.leeholmes.com/blog/GetTheOwnerOfAProcessInPowerShellPInvokeAndRefOutParameters.aspx
  43: function Invoke-Win32([string] $dllName, [Type] $returnType, 
  44:    [string] $methodName, [Type[]] $parameterTypes, [Object[]] $parameters) 
  45: {
  46:    ## Begin to build the dynamic assembly
  47:    $domain = [AppDomain]::CurrentDomain
  48:    $name = New-Object Reflection.AssemblyName 'PInvokeAssembly'
  49:    $assembly = $domain.DefineDynamicAssembly($name, 'Run') 
  50:    $module = $assembly.DefineDynamicModule('PInvokeModule')
  51:    $type = $module.DefineType('PInvokeType', "Public,BeforeFieldInit")
  52:  
  53:    ## Go through all of the parameters passed to us.  As we do this, 
  54:    ## we clone the user's inputs into another array that we will use for
  55:    ## the P/Invoke call.  
  56:    $inputParameters = @()
  57:    $refParameters = @()
  58:    
  59:    for($counter = 1; $counter -le $parameterTypes.Length; $counter++) 
  60:    {
  61:       ## If an item is a PSReference, then the user 
  62:       ## wants an [out] parameter.
  63:       if($parameterTypes[$counter - 1] -eq [Ref])
  64:       {
  65:          ## Remember which parameters are used for [Out] parameters 
  66:          $refParameters += $counter
  67:  
  68:          ## On the cloned array, we replace the PSReference type with the 
  69:          ## .Net reference type that represents the value of the PSReference, 
  70:          ## and the value with the value held by the PSReference. 
  71:          $parameterTypes[$counter - 1] = 
  72:             $parameters[$counter - 1].Value.GetType().MakeByRefType()
  73:          $inputParameters += $parameters[$counter - 1].Value
  74:       }
  75:       else
  76:       {
  77:          ## Otherwise, just add their actual parameter to the
  78:          ## input array.
  79:          $inputParameters += $parameters[$counter - 1]
  80:       }
  81:    }
  82:  
  83:    ## Define the actual P/Invoke method, adding the [Out] 
  84:    ## attribute for any parameters that were originally [Ref] 
  85:    ## parameters.
  86:    $method = $type.DefineMethod($methodName, 'Public,HideBySig,Static,PinvokeImpl', 
  87:       $returnType, $parameterTypes) 
  88:    foreach($refParameter in $refParameters)
  89:    {
  90:       $method.DefineParameter($refParameter, "Out", $null)
  91:    }
  92:  
  93:    ## Apply the P/Invoke constructor
  94:    $ctor = [Runtime.InteropServices.DllImportAttribute].GetConstructor([string])
  95:    $attr = New-Object Reflection.Emit.CustomAttributeBuilder $ctor, $dllName
  96:    $method.SetCustomAttribute($attr)
  97:  
  98:    ## Create the temporary type, and invoke the method.
  99:    $realType = $type.CreateType() 
 100:    $realType.InvokeMember($methodName, 'Public,Static,InvokeMethod', $null, $null, 
 101:       $inputParameters)
 102:  
 103:    ## Finally, go through all of the reference parameters, and update the
 104:    ## values of the PSReference objects that the user passed in. 
 105:    foreach($refParameter in $refParameters)
 106:    {
 107:       $parameters[$refParameter - 1].Value = $inputParameters[$refParameter - 1]
 108:    }
 109: }
 110:  
 111: function SendMessage([IntPtr] $hWnd, [Int32] $message, [Int32] $wParam, [Int32] $lParam) 
 112: {
 113:     $parameterTypes = [IntPtr], [Int32], [Int32], [Int32]
 114:     $parameters = $hWnd, $message, $wParam, $lParam
 115:  
 116:     Invoke-Win32 "user32.dll" ([Int32]) "SendMessage" $parameterTypes $parameters 
 117: }
 118:  
 119: function GetConsoleWindow()
 120: {
 121:     Invoke-Win32 "kernel32" ([IntPtr]) "GetConsoleWindow"
 122: }

用PowerShell“类型扩展”功能来为System.Console做“.Icon”属性一定也很有趣。那样我就会运行[System.Console]::Icon = "something.ico"不过我把这个任务留给读者们来练习。

clip_image007

记住,我们不会只说不做。

Comments (1)

  1. Oliver Feng says:

    超赞!

Skip to main content