//----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // Implements ShowCommandHelper // //----------------------------------------------------------------------- namespace Microsoft.PowerShell.Commands.ShowCommandInternal { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Management.Automation; using System.Reflection; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Threading; using Microsoft.Management.UI; using Microsoft.Management.UI.Internal; using Microsoft.Management.UI.Internal.ShowCommand; using Microsoft.PowerShell.Commands.ShowCommandExtension; /// /// Implements the WPF window part of the show-command cmdlet /// internal class ShowCommandHelper : IDisposable { #region fields internal const string CommandTypeSegment = " -CommandType Cmdlet, Function, Script, ExternalScript, Workflow"; /// /// Method that will return the dialog from ShowAllModulesWindow or ShowCommandWindow. /// This is necessary because the PlainInvokeAndShowDialog thread starter cannot receive parameters /// private DispatcherOperationCallback methodThatReturnsDialog; /// /// Event set when the window is closed /// private AutoResetEvent windowClosed = new AutoResetEvent(false); /// /// Event set when help is needed /// private AutoResetEvent helpNeeded = new AutoResetEvent(false); /// /// Event set when it is necessary to import a module /// private AutoResetEvent importModuleNeeded = new AutoResetEvent(false); /// /// Event set when the window is loaded /// private AutoResetEvent windowLoaded = new AutoResetEvent(false); /// /// String with the command that needs help set when helpNeeded is set /// private string commandNeedingHelp; /// /// String with the command name that needs to import a module /// private string commandNeedingImportModule; /// /// String with the module name that needs to be imported /// private string parentModuleNeedingImportModule; /// /// String with the selected module at the time a module needs to be imported /// private string selectedModuleNeedingImportModule; /// /// Keeps the window for the implementation of CloseWindow /// private Window window; /// /// host window, if any /// private Window hostWindow; /// /// ViewModel when showing all modules /// private AllModulesViewModel allModulesViewModel; /// /// ViewModel when showing a single command /// private CommandViewModel commandViewModel; /// /// true when the window is closed with cancel /// private bool dialogCanceled = true; #endregion fields #region GetSerializedCommand script private const string ScriptGetSerializedCommand = @" Function PSGetSerializedShowCommandInfo { Function GetParameterType { param ( [Type] $parameterType) $returnParameterType = new-object PSObject $returnParameterType | Add-Member -MemberType NoteProperty -Name ""FullName"" -Value $parameterType.FullName $returnParameterType | Add-Member -MemberType NoteProperty -Name ""IsEnum"" -Value $parameterType.IsEnum $returnParameterType | Add-Member -MemberType NoteProperty -Name ""IsArray"" -Value $parameterType.IsArray if ($parameterType.IsEnum) { $enumValues = [System.Enum]::GetValues($parameterType) } else { $enumValues = [string[]] @() } $returnParameterType | Add-Member -MemberType NoteProperty -Name ""EnumValues"" -Value $enumValues if ($parameterType.IsArray) { $hasFlagAttribute = ($parameterType.GetCustomAttributes([System.FlagsAttribute], $true).Length -gt 0) # Recurse into array elements. $elementType = GetParameterType($parameterType.GetElementType()) } else { $hasFlagAttribute = $false $elementType = $null } $returnParameterType | Add-Member -MemberType NoteProperty -Name ""HasFlagAttribute"" -Value $hasFlagAttribute $returnParameterType | Add-Member -MemberType NoteProperty -Name ""ElementType"" -Value $elementType if (!($parameterType.IsEnum) -and !($parameterType.IsArray)) { $implementsDictionary = [System.Collections.IDictionary].IsAssignableFrom($parameterType) } else { $implementsDictionary = $false } $returnParameterType | Add-Member -MemberType NoteProperty -Name ""ImplementsDictionary"" -Value $implementsDictionary return $returnParameterType } Function GetParameterInfo { param ( $parameters) [PSObject[]] $parameterInfos = @() foreach ($parameter in $parameters) { $parameterInfo = new-object PSObject $parameterInfo | Add-Member -MemberType NoteProperty -Name ""Name"" -Value $parameter.Name $parameterInfo | Add-Member -MemberType NoteProperty -Name ""IsMandatory"" -Value $parameter.IsMandatory $parameterInfo | Add-Member -MemberType NoteProperty -Name ""ValueFromPipeline"" -Value $parameter.ValueFromPipeline $parameterInfo | Add-Member -MemberType NoteProperty -Name ""Position"" -Value $parameter.Position $parameterInfo | Add-Member -MemberType NoteProperty -Name ""ParameterType"" -Value (GetParameterType($parameter.ParameterType)) $hasParameterSet = $false [string[]] $validValues = @() if ($PSVersionTable.PSVersion.Major -gt 2) { $validateSetAttributes = $parameter.Attributes | Where { [ValidateSet].IsAssignableFrom($_.GetType()) } if (($validateSetAttributes -ne $null) -and ($validateSetAttributes.Count -gt 0)) { $hasParameterSet = $true $validValues = $validateSetAttributes[0].ValidValues } } $parameterInfo | Add-Member -MemberType NoteProperty -Name ""HasParameterSet"" -Value $hasParameterSet $parameterInfo | Add-Member -MemberType NoteProperty -Name ""ValidParamSetValues"" -Value $validValues $parameterInfos += $parameterInfo } return (,$parameterInfos) } Function GetParameterSets { param ( [System.Management.Automation.CommandInfo] $cmdInfo ) $parameterSets = $null try { $parameterSets = $cmdInfo.ParameterSets } catch [System.InvalidOperationException] { } catch [System.Management.Automation.PSNotSupportedException] { } catch [System.Management.Automation.PSNotImplementedException] { } if (($parameterSets -eq $null) -or ($parameterSets.Count -eq 0)) { return (,@()) } [PSObject[]] $returnParameterSets = @() foreach ($parameterSet in $parameterSets) { $parameterSetInfo = new-object PSObject $parameterSetInfo | Add-Member -MemberType NoteProperty -Name ""Name"" -Value $parameterSet.Name $parameterSetInfo | Add-Member -MemberType NoteProperty -Name ""IsDefault"" -Value $parameterSet.IsDefault $parameterSetInfo | Add-Member -MemberType NoteProperty -Name ""Parameters"" -Value (GetParameterInfo($parameterSet.Parameters)) $returnParameterSets += $parameterSetInfo } return (,$returnParameterSets) } Function GetModuleInfo { param ( [System.Management.Automation.CommandInfo] $cmdInfo ) if ($cmdInfo.ModuleName -ne $null) { $moduleName = $cmdInfo.ModuleName } else { $moduleName = """" } $moduleInfo = new-object PSObject $moduleInfo | Add-Member -MemberType NoteProperty -Name ""Name"" -Value $moduleName return $moduleInfo } Function ConvertToShowCommandInfo { param ( [System.Management.Automation.CommandInfo] $cmdInfo ) $showCommandInfo = new-object PSObject $showCommandInfo | Add-Member -MemberType NoteProperty -Name ""Name"" -Value $cmdInfo.Name $showCommandInfo | Add-Member -MemberType NoteProperty -Name ""ModuleName"" -Value $cmdInfo.ModuleName $showCommandInfo | Add-Member -MemberType NoteProperty -Name ""Module"" -Value (GetModuleInfo($cmdInfo)) $showCommandInfo | Add-Member -MemberType NoteProperty -Name ""CommandType"" -Value $cmdInfo.CommandType $showCommandInfo | Add-Member -MemberType NoteProperty -Name ""Definition"" -Value $cmdInfo.Definition $showCommandInfo | Add-Member -MemberType NoteProperty -Name ""ParameterSets"" -Value (GetParameterSets($cmdInfo)) return $showCommandInfo } $commandList = @(""Cmdlet"", ""Function"", ""Script"", ""ExternalScript"") if ($PSVersionTable.PSVersion.Major -gt 2) { $commandList += ""Workflow"" } foreach ($command in @(Get-Command -CommandType $commandList)) { Write-Output (ConvertToShowCommandInfo($command)) } }"; #endregion #region constructor and destructor /// /// Prevents a default instance of the ShowCommandHelper class from being created /// private ShowCommandHelper() { } /// /// Finalizes an instance of the ShowCommandHelper class /// ~ShowCommandHelper() { this.Dispose(false); } #endregion constructor and destructor #region properties called using reflection /// /// Gets the Screen Width /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private static double ScreenWidth { get { return System.Windows.SystemParameters.PrimaryScreenWidth; } } /// /// Gets the Screen Height /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private static double ScreenHeight { get { return System.Windows.SystemParameters.PrimaryScreenHeight; } } /// /// Gets the event set when the show-command window is closed /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private AutoResetEvent WindowClosed { get { return this.windowClosed; } } /// /// Gets the event set when help is needed for a command /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private AutoResetEvent HelpNeeded { get { return this.helpNeeded; } } /// /// Gets the event set when it is necessary to import a module /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private AutoResetEvent ImportModuleNeeded { get { return this.importModuleNeeded; } } /// /// Gets the event set when the window is loaded /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private AutoResetEvent WindowLoaded { get { return this.windowLoaded; } } /// /// Gets the command needing help when HelpNeeded is set /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private string CommandNeedingHelp { get { return this.commandNeedingHelp; } } /// /// Gets the module we want to import /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private string ParentModuleNeedingImportModule { get { return this.parentModuleNeedingImportModule; } } /// /// Gets a value indicating whether there is a host window /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private bool HasHostWindow { get { return this.hostWindow != null; } } #endregion properties called using reflection #region public Dispose /// /// Dispose method in IDisposable /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } #endregion public Dispose #region internal static methods called using reflection from show-command and directly from ISE /// /// Sets the text in the clipboard /// /// text to set the clipboard to internal static void SetClipboardText(string text) { try { Clipboard.SetText(text); } catch (System.Runtime.InteropServices.COMException) { // This is the recommended way to set clipboard text System.Threading.Thread.Sleep(0); try { Clipboard.SetText(text); } catch (System.Runtime.InteropServices.COMException) { } } } /// /// Gets the command to be run to get commands and imported modules /// /// Boolean flag determining whether Show-Command is queried in the local or remote runspace scenario /// Boolean flag to indicate that it is the second attempt to query Show-Command data /// the command to be run to get commands and imported modules internal static string GetShowAllModulesCommand(bool isRemoteRunspace = false, bool isFirstChance = true) { string scriptBase; if (isRemoteRunspace) { if (isFirstChance) { // Return command to run. scriptBase = "@(Get-Command " + ShowCommandHelper.CommandTypeSegment + @" -ShowCommandInfo)"; } else { // Return script to run. scriptBase = GetSerializedCommandScript(); } } else { scriptBase = "@(Get-Command " + ShowCommandHelper.CommandTypeSegment + ")"; } scriptBase += ShowCommandHelper.GetGetModuleSuffix(); return scriptBase; } /// /// Retrieves the script for Get-SerializedCommand from local machine /// /// String representation of the script for Get-SerializedCommand private static string GetSerializedCommandScript() { return string.Format(CultureInfo.InvariantCulture, "@({0};{1};{2})", ScriptGetSerializedCommand, @"PSGetSerializedShowCommandInfo", @"Remove-Item -Path 'function:\PSGetSerializedShowCommandInfo' -Force"); } /// /// Gets the command to be run to in order to import a module and refresh the command data /// /// module we want to import /// Boolean flag determining whether Show-Command is queried in the local or remote runspace scenario /// Boolean flag to indicate that it is the second attempt to query Show-Command data /// the command to be run to in order to import a module and refresh the command data internal static string GetImportModuleCommand(string module, bool isRemoteRunspace = false, bool isFirstChance = true) { string scriptBase = "Import-Module " + ShowCommandHelper.SingleQuote(module); if (isRemoteRunspace) { if (isFirstChance) { scriptBase += ";@(Get-Command " + ShowCommandHelper.CommandTypeSegment + @" -ShowCommandInfo )"; } else { scriptBase += GetSerializedCommandScript(); } } else { scriptBase += ";@(Get-Command " + ShowCommandHelper.CommandTypeSegment + ")"; } scriptBase += ShowCommandHelper.GetGetModuleSuffix(); return scriptBase; } /// /// gets the command to be run in order to show help for a command /// /// command we want to get help from /// the command to be run in order to show help for a command internal static string GetHelpCommand(string command) { return "Get-Help " + ShowCommandHelper.SingleQuote(command); } /// /// Constructs a dictionary of imported modules based on the module names /// /// the imported modules /// a dictionary of imported modules based on the module names internal static Dictionary GetImportedModulesDictionary(object[] moduleObjects) { Dictionary returnValue = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (PSObject rawModule in moduleObjects) { ShowCommandModuleInfo wrappedModule = null; PSModuleInfo module = rawModule.BaseObject as PSModuleInfo; if (module != null) { wrappedModule = new ShowCommandModuleInfo(module); } else { wrappedModule = new ShowCommandModuleInfo(rawModule); } // It is probably an issue somewhere else that a module would show up twice in the list, but we want to avoid // throwing an exception regarding that in returnValue.Add if(!returnValue.ContainsKey(wrappedModule.Name)) { returnValue.Add(wrappedModule.Name, wrappedModule); } } return returnValue; } /// /// Constructs a list of commands out of /// /// the results of a get-command command /// a list of commands out of internal static List GetCommandList(object[] commandObjects) { List returnValue = new List(); foreach (PSObject rawCommand in commandObjects) { CommandInfo command = rawCommand.BaseObject as CommandInfo; if(command != null) { returnValue.Add(new ShowCommandCommandInfo(command)); } else { PSObject obj = rawCommand as PSObject; if(obj != null) { returnValue.Add(new ShowCommandCommandInfo(obj)); } } } return returnValue; } /// /// Constructs an array of objects out of /// /// The result of a get-command command /// An array of objects out of internal static object[] ObjectArrayFromObjectCollection(object commandObjects) { object[] objectArray = commandObjects as object[]; if(objectArray == null) { objectArray = ((System.Collections.ArrayList)commandObjects).ToArray(); } return objectArray; } /// /// Called after a module in is imported to refresh the view model. /// Gets a new AllModulesViewModel populated with and . /// The is used to cleanup event listening in the old view model and to copy NoCommonParameters. /// The new ViewModel will have the command selected according to , /// and . /// /// the viewModel before the module was imported /// the list of imported modules /// the list of commands /// the name of the module that was selected in /// the name of the module that was imported /// the name of the command that was selected in /// The new ViewModel based on and . internal static AllModulesViewModel GetNewAllModulesViewModel(AllModulesViewModel oldViewModel, Dictionary importedModules, IEnumerable commands, string selectedModuleNeedingImportModule, string parentModuleNeedingImportModule, string commandNeedingImportModule) { string oldFilter = null; if (oldViewModel.SelectedModule != null) { // this will allow the old view model to stop listening for events before we // replace it with a new view model oldViewModel.SelectedModule.SelectedCommand = null; oldViewModel.SelectedModule = null; oldFilter = oldViewModel.CommandNameFilter; } AllModulesViewModel returnValue = new AllModulesViewModel(importedModules, commands, oldViewModel.NoCommonParameter); if (!String.IsNullOrEmpty(oldFilter)) { returnValue.CommandNameFilter = oldFilter; } if (selectedModuleNeedingImportModule == null || parentModuleNeedingImportModule == null) { return returnValue; } ModuleViewModel moduleToSelect = returnValue.Modules.Find( new Predicate(delegate(ModuleViewModel module) { return module.Name.Equals(selectedModuleNeedingImportModule, StringComparison.OrdinalIgnoreCase) ? true : false; })); if (moduleToSelect == null) { return returnValue; } returnValue.SelectedModule = moduleToSelect; CommandViewModel commandToSelect = moduleToSelect.Commands.Find( new Predicate(delegate(CommandViewModel command) { return command.ModuleName.Equals(parentModuleNeedingImportModule, StringComparison.OrdinalIgnoreCase) && command.Name.Equals(commandNeedingImportModule, StringComparison.OrdinalIgnoreCase) ? true : false; })); if (commandToSelect == null) { return returnValue; } moduleToSelect.SelectedCommand = commandToSelect; return returnValue; } /// /// Gets an error message to be displayed when failed to import a module /// /// command belonging to the module to import /// module to import /// error importing the module /// an error message to be displayed when failed to import a module internal static string GetImportModuleFailedMessage(string command, string module, string error) { return String.Format( CultureInfo.CurrentUICulture, ShowCommandResources.ImportModuleFailedFormat, command, module, error); } /// /// Single quotes /// /// string to quote /// single quoted internal static string SingleQuote(string str) { if (str == null) { str = String.Empty; } return "\'" + System.Management.Automation.Language.CodeGeneration.EscapeSingleQuotedStringContent(str) + "\'"; } #endregion internal static methods called using reflection from show-command and directly from ISE #region internal static methods used internally in this assembly /// /// Gets the host window, if it is present or null if it is not /// /// cmdlet calling this method /// the host window, if it is present or null if it is not internal static Window GetHostWindow(PSCmdlet cmdlet) { PSPropertyInfo windowProperty = cmdlet.Host.PrivateData.Properties["Window"]; if (windowProperty == null) { return null; } try { return windowProperty.Value as Window; } catch (ExtendedTypeSystemException) { return null; } } #endregion internal static methods used internally in this assembly #region static private methods used only on this file /// /// Gets a property value using reflection /// /// type containing the property /// object containing the property (null for a static property) /// name of property to get /// flags passed to reflection /// /// property value or null if it was not able to retrieve it. This method is not suitable to return a property value that might be null. /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from a method called using reflection")] private static object GetPropertyValue(Type type, object obj, string propertyName, BindingFlags bindingFlags) { PropertyInfo property = type.GetProperty(propertyName, bindingFlags); if (property == null) { return null; } try { return property.GetValue(obj, new object[] { }); } catch (ArgumentException) { return null; } catch (TargetException) { return null; } catch (TargetParameterCountException) { return null; } catch (MethodAccessException) { return null; } catch (TargetInvocationException) { return null; } } /// /// Sets a property value using reflection /// /// type containing the property /// object containing the property (null for a static property) /// name of property to set /// value to set the property with /// flags passed to reflection /// true if it was able to set [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from a method called using reflection")] private static bool SetPropertyValue(Type type, object obj, string propertyName, object value, BindingFlags bindingFlags) { PropertyInfo property = type.GetProperty(propertyName, bindingFlags); if (property == null) { return false; } try { property.SetValue(obj, value, new object[] { }); } catch (ArgumentException) { return false; } catch (TargetException) { return false; } catch (TargetParameterCountException) { return false; } catch (MethodAccessException) { return false; } catch (TargetInvocationException) { return false; } return true; } /// /// Gets the suffix that adds imported modules to a command /// /// the suffix that adds imported modules to a command private static string GetGetModuleSuffix() { return ",@(get-module)"; } #endregion static private methods used only on this file #region private methods called using reflection from show-command /// /// Gets the command to be run when calling show-command for a particular command /// /// the particular command we are running show-command on /// true if we want to include aliases and retrieve modules /// the command to be run when calling show-command for a particular command [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private static string GetShowCommandCommand(string commandName, bool includeAliasAndModules) { string quotedCommandName = ShowCommandHelper.SingleQuote(commandName); return "@(get-command " + quotedCommandName + " " + ShowCommandHelper.CommandTypeSegment + (includeAliasAndModules ? ",Alias" : String.Empty) + ")" + (includeAliasAndModules ? ShowCommandHelper.GetGetModuleSuffix() : String.Empty); } /// /// Gets a CommandViewModel of a CommandInfo /// /// command we want to get a CommandViewModel of /// true if we do not want common parameters /// the loaded modules /// True to qualify command with module name in GetScript /// a CommandViewModel of a CommandInfo [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private static object GetCommandViewModel(ShowCommandCommandInfo command, bool noCommonParameter, Dictionary importedModules, bool moduleQualify) { CommandViewModel returnValue = CommandViewModel.GetCommandViewModel(new ModuleViewModel(command.ModuleName, importedModules), command, noCommonParameter); returnValue.ModuleQualifyCommandName = moduleQualify; return returnValue; } /// /// Dispatches a message to the window for it to activate /// /// window to be activated [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from ActivateWindow() which is called using reflection")] private static void ActivateWindow(Window window) { window.Dispatcher.Invoke( new SendOrPostCallback( delegate(object ignored) { window.Activate(); }), String.Empty); } /// /// Sets a property in ISE that will allow the command to be run /// /// command to be run /// true if it was possible to set the pending ISE command [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private bool SetPendingISECommand(string command) { Diagnostics.Assert(this.hostWindow != null, "The caller checks that"); Type internalHostType = this.hostWindow.GetType().Assembly.GetType("Microsoft.Windows.PowerShell.Gui.Internal.PSGInternalHost"); if (internalHostType == null) { return false; } object current = GetPropertyValue(internalHostType, null, "Current", BindingFlags.Public | BindingFlags.Static); if (current == null) { return false; } object powerShellTabs = GetPropertyValue(current.GetType(), current, "PowerShellTabs", BindingFlags.Public | BindingFlags.Instance); if (powerShellTabs == null) { return false; } object selectedPowerShellTab = GetPropertyValue(powerShellTabs.GetType(), powerShellTabs, "SelectedPowerShellTab", BindingFlags.Public | BindingFlags.Instance); if (selectedPowerShellTab == null) { return false; } return SetPropertyValue(selectedPowerShellTab.GetType(), selectedPowerShellTab, "PendingCommand", command, BindingFlags.NonPublic | BindingFlags.Instance); } /// /// Shows the window listing cmdlets /// /// cmdlet calling this method /// All loaded modules /// commands to be listed /// true if we should not show common parameters /// window width /// window height /// true if the GUI should mention ok instead of run [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private void ShowAllModulesWindow(PSCmdlet cmdlet, Dictionary importedModules, IEnumerable commands, bool noCommonParameter, double windowWidth, double windowHeight, bool passThrough) { this.methodThatReturnsDialog = new DispatcherOperationCallback(delegate(object ignored) { Diagnostics.Assert(commands.GetEnumerator().MoveNext(), "there is always at least one command"); ShowAllModulesWindow allModulesWindow = new ShowAllModulesWindow(); this.allModulesViewModel = new AllModulesViewModel(importedModules, commands, noCommonParameter); this.SetupButtonEvents(allModulesWindow.Run, allModulesWindow.Copy, allModulesWindow.Cancel, passThrough); this.SetupWindow(allModulesWindow); this.SetupViewModel(); CommonHelper.SetStartingPositionAndSize( allModulesWindow, ShowCommandSettings.Default.ShowCommandsTop, ShowCommandSettings.Default.ShowCommandsLeft, windowWidth != 0.0 && windowWidth > allModulesWindow.MinWidth ? windowWidth : ShowCommandSettings.Default.ShowCommandsWidth, windowHeight != 0.0 && windowHeight > allModulesWindow.MinHeight ? windowHeight : ShowCommandSettings.Default.ShowCommandsHeight, allModulesWindow.Width, allModulesWindow.Height, ShowCommandSettings.Default.ShowCommandsWindowMaximized); return allModulesWindow; }); this.CallShowDialog(cmdlet); } /// /// Calls ShowsDialog on methodThatReturnsDialog either in a separate thread or dispatched /// to the hostWindow thread if there is a hostWindow /// /// cmdlet used to retrieve the host window [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from a method called using reflection")] private void CallShowDialog(PSCmdlet cmdlet) { this.hostWindow = ShowCommandHelper.GetHostWindow(cmdlet); if (this.hostWindow == null) { Thread guiThread = new Thread(new ThreadStart(this.PlainInvokeAndShowDialog)); guiThread.SetApartmentState(ApartmentState.STA); guiThread.Start(); return; } this.hostWindow.Dispatcher.Invoke( new SendOrPostCallback( delegate(object ignored) { Window childWindow = (Window)this.methodThatReturnsDialog.Invoke(null); childWindow.Owner = this.hostWindow; childWindow.Show(); }), String.Empty); } /// /// Called from CallMethodThatShowsDialog as the thread start when there is no host window /// private void PlainInvokeAndShowDialog() { ((Window)this.methodThatReturnsDialog.Invoke(null)).ShowDialog(); } /// /// Shows the window for the cmdlet /// /// cmdlet calling this method /// command to show in the window /// window width /// window height /// true if the GUI should mention ok instead of run [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private void ShowCommandWindow(PSCmdlet cmdlet, object commandViewModelObj, double windowWidth, double windowHeight, bool passThrough) { this.methodThatReturnsDialog = new DispatcherOperationCallback(delegate(object ignored) { Diagnostics.Assert(commandViewModelObj != null, "verified by caller"); this.commandViewModel = (CommandViewModel)commandViewModelObj; ShowCommandWindow showCommandWindow = new ShowCommandWindow(); this.commandViewModel.HelpNeeded += new EventHandler(this.CommandNeedsHelp); showCommandWindow.DataContext = this.commandViewModel; this.SetupButtonEvents(showCommandWindow.Run, showCommandWindow.Copy, showCommandWindow.Cancel, passThrough); this.SetupWindow(showCommandWindow); CommonHelper.SetStartingPositionAndSize( showCommandWindow, ShowCommandSettings.Default.ShowOneCommandTop, ShowCommandSettings.Default.ShowOneCommandLeft, windowWidth != 0.0 && windowWidth > showCommandWindow.MinWidth ? windowWidth : ShowCommandSettings.Default.ShowOneCommandWidth, windowHeight != 0.0 && windowHeight > showCommandWindow.MinHeight ? windowHeight : ShowCommandSettings.Default.ShowOneCommandHeight, showCommandWindow.Width, showCommandWindow.Height, ShowCommandSettings.Default.ShowOneCommandWindowMaximized); return showCommandWindow; }); this.CallShowDialog(cmdlet); } /// /// Called when the module importation is done /// /// all modules currently imported /// commands to be displayed [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private void ImportModuleDone(Dictionary importedModules, IEnumerable commands) { this.allModulesViewModel.WaitMessageDisplayed = false; if (this.window != null) { this.window.Dispatcher.Invoke( new SendOrPostCallback( delegate(object ignored) { this.allModulesViewModel = ShowCommandHelper.GetNewAllModulesViewModel( this.allModulesViewModel, importedModules, commands, this.selectedModuleNeedingImportModule, this.parentModuleNeedingImportModule, this.commandNeedingImportModule); this.SetupViewModel(); }), String.Empty); } } /// /// Called when the module importation has failed /// /// reason why the module importation failed [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private void ImportModuleFailed(Exception reason) { this.allModulesViewModel.WaitMessageDisplayed = false; if (this.window != null) { this.window.Dispatcher.Invoke( new SendOrPostCallback( delegate(object ignored) { string message = ShowCommandHelper.GetImportModuleFailedMessage( this.commandNeedingImportModule, this.parentModuleNeedingImportModule, reason.Message); MessageBox.Show(this.window, message, ShowCommandResources.ShowCommandError, MessageBoxButton.OK, MessageBoxImage.Error); }), String.Empty); } } /// /// Called when the results or get-help are ready in order to display the help window for a command /// /// results of a get-help call [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private void DisplayHelp(Collection getHelpResults) { if (this.window != null && getHelpResults != null && getHelpResults.Count > 0) { this.window.Dispatcher.Invoke( new SendOrPostCallback( delegate(object ignored) { HelpWindow help = new HelpWindow(getHelpResults[0]); help.Owner = this.window; help.Show(); }), String.Empty); } } /// /// Activates this.window /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private void ActivateWindow() { if (this.window != null) { ShowCommandHelper.ActivateWindow(this.window); } } /// /// returns the script to execute if dialog has not been canceled /// /// the script to execute if dialog has not been canceled [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")] private string GetScript() { if (this.dialogCanceled) { return null; } return this.InternalGetScript(); } #endregion private methods called using reflection from show-command #region instance private methods used only on this file /// /// Sets up window settings common between the two flavors of show-command /// /// the window being displayed [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from ShowAllModulesWindow and ShowCommandWindow which are called with reflection")] private void SetupWindow(Window commandWindow) { this.window = commandWindow; this.window.Closed += new EventHandler(this.Window_Closed); this.window.Loaded += new RoutedEventHandler(this.Window_Loaded); } /// /// Handles the SelectedCommandInSelectedModuleNeedsImportModule event /// /// event sender /// event arguments private void CommandNeedsImportModule(object sender, ImportModuleEventArgs e) { this.commandNeedingImportModule = e.CommandName; this.parentModuleNeedingImportModule = e.ParentModuleName; this.selectedModuleNeedingImportModule = e.SelectedModuleName; this.allModulesViewModel.WaitMessageDisplayed = true; this.ImportModuleNeeded.Set(); } /// /// Handles the SelectedCommandInSelectedModuleNeedsHelp event /// /// event sender /// event arguments private void CommandNeedsHelp(object sender, HelpNeededEventArgs e) { this.commandNeedingHelp = e.CommandName; this.HelpNeeded.Set(); } /// /// Called when the window is closed to set this.dialogCanceled /// /// event sender /// event arguments private void Window_Closed(object sender, EventArgs e) { if (this.hostWindow != null) { this.hostWindow.Focus(); } this.window = null; this.windowClosed.Set(); } /// /// Called when the window is loaded to set this.Window_Loaded /// /// event sender /// event arguments private void Window_Loaded(object sender, RoutedEventArgs e) { this.window.Loaded -= new RoutedEventHandler(this.Window_Loaded); this.windowLoaded.Set(); } /// /// Sets up event listening on the buttons /// /// button to run command /// button to copy command code /// button to close window /// true to change the text of Run to OK [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from methods called using reflection")] private void SetupButtonEvents(Button run, Button copy, Button cancel, bool passThrough) { if (passThrough) { run.Content = ShowCommandResources.ActionButtons_Button_Ok; } run.Click += new RoutedEventHandler(this.Buttons_RunClick); copy.Click += new RoutedEventHandler(this.Buttons_CopyClick); cancel.Click += new RoutedEventHandler(this.Buttons_CancelClick); } /// /// Sets up event listening for a new viewModel /// private void SetupViewModel() { this.allModulesViewModel.SelectedCommandInSelectedModuleNeedsHelp += new EventHandler(this.CommandNeedsHelp); this.allModulesViewModel.SelectedCommandInSelectedModuleNeedsImportModule += new EventHandler(this.CommandNeedsImportModule); this.window.DataContext = this.allModulesViewModel; } /// /// Copies the script into the clipboard /// /// event sender /// event arguments private void Buttons_CopyClick(object sender, RoutedEventArgs e) { string script = this.InternalGetScript(); if (script == null) { return; } this.window.Dispatcher.Invoke(new ThreadStart(delegate { ShowCommandHelper.SetClipboardText(script); })); } /// /// Sets a successful dialog result and then closes the window /// /// event sender /// event arguments private void Buttons_RunClick(object sender, RoutedEventArgs e) { this.dialogCanceled = false; this.CloseWindow(); } /// /// Closes the window /// /// event sender /// event arguments private void Buttons_CancelClick(object sender, RoutedEventArgs e) { this.CloseWindow(); } /// /// closes the window /// private void CloseWindow() { if (this.window == null) { return; } this.window.Dispatcher.Invoke(new ThreadStart(delegate { // This can happen if ISE is closed while show-command is up if (this.window != null) { this.window.Close(); } })); } /// /// Showing a MessageBox when user type a invalidate command name. /// /// error message private void ShowErrorString(string errorString) { if (errorString != null && errorString.Trim().Length > 0) { MessageBox.Show( String.Format( CultureInfo.CurrentUICulture, ShowCommandResources.EndProcessingErrorMessage, errorString), "Show-Command", MessageBoxButton.OK, MessageBoxImage.Error); } } /// /// returns the script to execute /// /// the script to execute private string InternalGetScript() { if (this.allModulesViewModel != null) { return this.allModulesViewModel.GetScript(); } if (this.commandViewModel == null) { return null; } return this.commandViewModel.GetScript(); } /// /// Implements IDisposable logic /// /// true if being called from Dispose private void Dispose(bool isDisposing) { if (isDisposing) { this.windowClosed.Dispose(); this.helpNeeded.Dispose(); this.windowLoaded.Dispose(); this.importModuleNeeded.Dispose(); } } #endregion instance private methods used only on this file } }