Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / MS / Internal / AppModel / OleCmdHelper.cs / 1 / OleCmdHelper.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // This is a helper class used for interop to process the // IOleCommandTarget calls in browser hosting scenario // // History: // 06/09/03: kusumav Moved from Application.cs to separate file. // //--------------------------------------------------------------------------- using System; using System.Collections; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows.Threading; using System.Windows; using System.Security; using System.Security.Permissions; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Navigation; using System.Windows.Controls; using MS.Internal.Documents; // DocumentApplicationDocumentViewer using MS.Internal.PresentationFramework; // SecurityHelper using MS.Internal.KnownBoxes; using MS.Win32; namespace MS.Internal.AppModel { #region OleCmdHelper class //// OleCmd helper class for processing IOleCommandTarget calls in browser hosting scenario // internal sealed class OleCmdHelper : MarshalByRefObject, IOleCmdMappingService { internal const int OLECMDERR_E_NOTSUPPORTED = unchecked((int)0x80040100), OLECMDERR_E_DISABLED = unchecked((int)0x80040101), OLECMDERR_E_UNKNOWNGROUP = unchecked((int)0x80040104); internal const uint CommandUnsupported = 0; internal const uint CommandEnabled = (uint)(UnsafeNativeMethods.OLECMDF.OLECMDF_ENABLED | UnsafeNativeMethods.OLECMDF.OLECMDF_SUPPORTED); internal const uint CommandDisabled = (uint)UnsafeNativeMethods.OLECMDF.OLECMDF_SUPPORTED; // IMPORTANT: Keep this in [....] with wcp\host\inc\hostservices.idl internal static readonly Guid CGID_ApplicationCommands = new Guid(0xebbc8a63, 0x8559, 0x4892, 0x97, 0xa8, 0x31, 0xe9, 0xb0, 0xe9, 0x85, 0x91); internal static readonly Guid CGID_EditingCommands = new Guid(0xc77ce45, 0xd1c, 0x4f2a, 0xb2, 0x93, 0xed, 0xd5, 0xe2, 0x7e, 0xba, 0x47); internal OleCmdHelper() { } ////// Critical:This code path enables you to add arbitrary commands /// to a mapping table which is a critical resource /// [SecurityCritical] void IOleCmdMappingService.AddMapping(uint olecmd, RoutedCommand command) { _oleCmdMappingTable.Value[olecmd] = command; } event EventHandler IOleCmdMappingService.UpdatingMappingTable { add { _updateMappingTable += value; } remove { _updateMappingTable -= value; } } ////// Critical: This code calls into _DoqueryStatus /// ////// The native code passes queries here only for the recognized command groups: /// standard (NULL), ApplicaitonCommands, EditingCommands. /// [SecurityCritical] internal void QueryStatus(Guid guidCmdGroup, uint cmdId, ref uint flags) { /***IMPORTANT: Make sure to return allowed and appropriate values according to the specification of IOleCommandTarget::QueryStatus(). In particular: - OLECMDF_SUPPORTED without OLECMDF_ENABLED should not be blindly returned for unrecognized commands. - Some code in IE treats OLECMDERR_E_xxx differently from generic failures. - E_NOTIMPL is not an acceptable return value. */ if (Application.Current == null || Application.IsShuttingDown == true) { Marshal.ThrowExceptionForHR(NativeMethods.E_FAIL); } // Get values from mapping here else mark them as disabled ==> // i.e "supported but not enabled" and is the equivalent of disabled since // there is no explicit "disabled" OLECMD flag IDictionary oleCmdMappingTable = GetOleCmdMappingTable(guidCmdGroup); if (oleCmdMappingTable == null) { Marshal.ThrowExceptionForHR(OleCmdHelper.OLECMDERR_E_UNKNOWNGROUP); } CommandWithArgument command = oleCmdMappingTable[cmdId] as CommandWithArgument; if (command == null) { flags = CommandUnsupported; return; } // Go through the Dispatcher in order to use its SynchronizationContext and also // so that any application exception caused during event routing is reported via // Dispatcher.UnhandledException. // The above code is not in the callback, because it throws, and we don't want the // application to get these exceptions. (The COM Interop layer turns them into HRESULTs.) bool enabled = (bool)Application.Current.Dispatcher.Invoke( DispatcherPriority.Send, new DispatcherOperationCallback(QueryEnabled), command); flags = enabled ? CommandEnabled : CommandDisabled; } ////// Critical: Calls the critical CommandWithArgument.QueryEnabled(). /// [SecurityCritical] private object QueryEnabled(object command) { if (Application.Current.MainWindow == null) return false; IInputElement target = FocusManager.GetFocusedElement(Application.Current.MainWindow); if (target == null) { // This will always succeed because Window is IInputElement target = (IInputElement)Application.Current.MainWindow; } return BooleanBoxes.Box(((CommandWithArgument)command).QueryEnabled(target, null)); } ////// Critical: This code calls into ExecCommandCallback helper /// ////// The native code passes here only commands of the recognized command groups: /// standard (NULL), ApplicaitonCommands, EditingCommands. /// [SecurityCritical] internal void ExecCommand(Guid guidCmdGroup, uint commandId, object arg) { if (Application.Current == null || Application.IsShuttingDown == true) { Marshal.ThrowExceptionForHR(NativeMethods.E_FAIL); } int hresult = (int)Application.Current.Dispatcher.Invoke( DispatcherPriority.Send, new DispatcherOperationCallback(ExecCommandCallback), new object[] { guidCmdGroup, commandId, arg }); // Note: ExecCommandCallback() returns an HRESULT instead of throwing for the reason // explained in QueryStatus(). if(hresult < 0) { Marshal.ThrowExceptionForHR(hresult); } } ////// Critical:This API calls into Execute /// [SecurityCritical] private object ExecCommandCallback(object arguments) { object[] args = (object[])arguments; Invariant.Assert(args.Length == 3); Guid guidCmdGroup = (Guid)args[0]; uint commandId = (uint)args[1]; object arg = args[2]; IDictionary oleCmdMappingTable = GetOleCmdMappingTable(guidCmdGroup); if (oleCmdMappingTable == null) return OLECMDERR_E_UNKNOWNGROUP; CommandWithArgument command = oleCmdMappingTable[commandId] as CommandWithArgument; if (command == null) return OLECMDERR_E_NOTSUPPORTED; if (Application.Current.MainWindow == null) return OLECMDERR_E_DISABLED; IInputElement target = FocusManager.GetFocusedElement(Application.Current.MainWindow); if (target == null) { // This will always succeed because Window is IInputElement target = (IInputElement)Application.Current.MainWindow; } return command.Execute(target, arg) ? NativeMethods.S_OK : OLECMDERR_E_DISABLED; } ////// Critical:This API accesses the commandmapping table and returns it /// TreatAsSafe: It returns a copy which is safe /// [SecurityCritical, SecurityTreatAsSafe] private IDictionary GetOleCmdMappingTable(Guid guidCmdGroup) { IDictionary mappingTable = null; if (guidCmdGroup.Equals(CGID_ApplicationCommands)) { EnsureApplicationCommandsTable(); mappingTable = _applicationCommandsMappingTable.Value; } else if(guidCmdGroup.Equals(Guid.Empty)) { EnsureOleCmdMappingTable(); mappingTable = _oleCmdMappingTable.Value; } else if (guidCmdGroup.Equals(CGID_EditingCommands)) { EnsureEditingCommandsTable(); mappingTable = _editingCommandsMappingTable.Value; } return mappingTable; } ////// Critical: This code initializes the OleCmdMappingTable which is a critical for /// set data structure /// TreatAsSafe: All the values that it adds are predefined handlers in this class /// no external values /// [SecurityCritical,SecurityTreatAsSafe] private void EnsureOleCmdMappingTable() { if (_oleCmdMappingTable.Value == null) { _oleCmdMappingTable.Value = new SortedList(10); //Add applevel commands here _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_SAVE, new CommandWithArgument(ApplicationCommands.Save)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_SAVEAS, new CommandWithArgument(ApplicationCommands.SaveAs)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_PRINT, new CommandWithArgument(ApplicationCommands.Print)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_CUT, new CommandWithArgument(ApplicationCommands.Cut)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_COPY, new CommandWithArgument(ApplicationCommands.Copy)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_PASTE, new CommandWithArgument(ApplicationCommands.Paste)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_PROPERTIES, new CommandWithArgument(ApplicationCommands.Properties)); //Set the Enabled property of Stop and Refresh commands correctly _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_REFRESH, new CommandWithArgument(NavigationCommands.Refresh)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_STOP, new CommandWithArgument(NavigationCommands.BrowseStop)); //Ensure the mapping table is up-to-date taking into consideration //any navigations that may be changed the input manager (which is currently //per root, so top level navs will require us to reconstruct the table) UpdateMappingTable(_oleCmdMappingTable.Value); } } ////// Critical: This code initializes the OleCmdMappingTable which is a critical for /// set data structure /// TreatAsSafe: All the values that it adds are predefined handlers in this class /// no external values /// [SecurityCritical, SecurityTreatAsSafe] private void EnsureApplicationCommandsTable() { if (_applicationCommandsMappingTable.Value == null) { /* we want to possible add 26 entries, so the capacity should be * 26/0.72 = 19 for default of 1.0 load factor*/ _applicationCommandsMappingTable.Value = new Hashtable(19); //Add applevel commands here // Note: The keys are added as uint type so that the default container comparer works // when we try to look up a command by a uint cmdid. _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Cut, new CommandWithArgument(ApplicationCommands.Cut)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Copy, new CommandWithArgument(ApplicationCommands.Copy)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Paste, new CommandWithArgument(ApplicationCommands.Paste)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_SelectAll, new CommandWithArgument(ApplicationCommands.SelectAll)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Find, new CommandWithArgument(ApplicationCommands.Find)); // Add standard navigation commands _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Refresh, new CommandWithArgument(NavigationCommands.Refresh)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Stop, new CommandWithArgument(NavigationCommands.BrowseStop)); // add document viewer commands _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Digitalsignatures_SignDocument, new CommandWithArgument(DocumentApplicationDocumentViewer.Sign)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Digitalsignatures_RequestSignature, new CommandWithArgument(DocumentApplicationDocumentViewer.RequestSigners)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Digitalsignatures_ViewSignature, new CommandWithArgument(DocumentApplicationDocumentViewer.ShowSignatureSummary)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Permission_Set, new CommandWithArgument(DocumentApplicationDocumentViewer.ShowRMPublishingUI)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Permission_View, new CommandWithArgument(DocumentApplicationDocumentViewer.ShowRMPermissions)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Permission_Restrict, new CommandWithArgument(DocumentApplicationDocumentViewer.ShowRMCredentialManager)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_In, new CommandWithArgument(NavigationCommands.IncreaseZoom)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_Out, new CommandWithArgument(NavigationCommands.DecreaseZoom)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_400, new CommandWithArgument(NavigationCommands.Zoom, 400)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_250, new CommandWithArgument(NavigationCommands.Zoom, 250)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_150, new CommandWithArgument(NavigationCommands.Zoom, 150)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_100, new CommandWithArgument(NavigationCommands.Zoom, 100)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_75, new CommandWithArgument(NavigationCommands.Zoom, 75)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_50, new CommandWithArgument(NavigationCommands.Zoom, 50)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_25, new CommandWithArgument(NavigationCommands.Zoom, 25)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_PageWidth, new CommandWithArgument(DocumentViewer.FitToWidthCommand)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_WholePage, new CommandWithArgument(DocumentViewer.FitToHeightCommand)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_TwoPages, new CommandWithArgument(DocumentViewer.FitToMaxPagesAcrossCommand, 2)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_Thumbnails, new CommandWithArgument(DocumentViewer.ViewThumbnailsCommand)); //Ensure the mapping table is up-to-date taking into consideration //any navigations that may be changed the input manager (which is currently //per root, so top level navs will require us to reconstruct the table) UpdateMappingTable(_applicationCommandsMappingTable.Value); } } ////// Critical: Initializes _editingCommandsMappingTable, which is a critical for set. /// TreatAsSafe: Only predefined commands are used. EditingCommands are enabled in partial trust. /// [SecurityCritical, SecurityTreatAsSafe] private void EnsureEditingCommandsTable() { if (_editingCommandsMappingTable.Value == null) { _editingCommandsMappingTable.Value = new SortedList(2); // Note: The keys are added as uint type so that the default container comparer works // when we try to look up a command by a uint cmdid. _editingCommandsMappingTable.Value.Add((uint)EditingCommandIds.Backspace, new CommandWithArgument(System.Windows.Documents.EditingCommands.Backspace)); _editingCommandsMappingTable.Value.Add((uint)EditingCommandIds.Delete, new CommandWithArgument(System.Windows.Documents.EditingCommands.Delete)); } } ////// Critical - creates a command binding. Performs an elevation to register the Binding. /// [SecurityCritical] private void UpdateMappingTable(IDictionary mappingTable) { if (_updateMappingTable != null) { _updateMappingTable(this, EventArgs.Empty); } Window window = Application.Current.MainWindow; if (window != null) { window.InputBindings.Add(new KeyBinding(NavigationCommands.Refresh, Key.F5, ModifierKeys.Control)); foreach (CommandWithArgument command in mappingTable.Values) { CommandBinding commandBinding ; // // if this is a secure command - a demand will be performed at // registration of the command binding. // So we perform an assert. // Considered safe - as we're only allowing registration of the command ( e.g. paste) // ISecureCommand secCommand = command.Command as ISecureCommand; if ( secCommand != null ) { secCommand.UserInitiatedPermission.Assert(); } try { commandBinding = new CommandBinding(command.Command); } finally { if (secCommand != null) CodeAccessPermission.RevertAssert(); } if (command.Command == ApplicationCommands.Properties) { commandBinding.CanExecute += new CanExecuteRoutedEventHandler(OnPropertiesQueryEnabled); commandBinding.Executed += new ExecutedRoutedEventHandler(OnPropertiesCommand); } window.CommandBindings.Add(commandBinding); } } } ////// This is the method that gets called when ApplicationCommands.Properties ExecutedRoutedEventHandler get called. /// /// assumptions: /// It should only get called if we are hosted in browser. /// private void OnPropertiesQueryEnabled(object sender, CanExecuteRoutedEventArgs args) { //only hookup the Properties Command if we are hosted in browser and this is a container bool isContainer = Application.Current.MimeType == MimeType.Document; args.CanExecute = (BrowserInteropHelper.IsBrowserHosted && isContainer); } ////// This is the method that gets called when ApplicationCommands.PropertiesCommand /// CommandEventInvokeHandlers get called. /// /// assumptions: /// It should only get called if we are hosted in browser, and if we are /// hosting a container. We do nothing for EXEs /// private void OnPropertiesCommand(object sender, ExecutedRoutedEventArgs execArgs) { // todo: // Task: 40616: MetaData/Properties - View Document Properties // The plan for containers is to wire up a winforms dialog that can // show properties for a package. I recommend having Application // create a method that can be overridden by DocumentApplication // which can respond to this command. The call would look like: // // Application.OnPropertiesCommand(sender, execArgs); // // The Application implementation would do nothing, satisfying xapp. } private SecurityCriticalDataForSet_oleCmdMappingTable; private SecurityCriticalDataForSet _applicationCommandsMappingTable; private SecurityCriticalDataForSet _editingCommandsMappingTable; private EventHandler _updateMappingTable; } #endregion OleCmdHelper class #region IOleCmdMappingService interface internal interface IOleCmdMappingService { void AddMapping(uint olecmd, RoutedCommand command); event EventHandler UpdatingMappingTable; } #endregion IOleCmdMappingService interface #region CommandAndArgument class /// /// This wrapper class helps store default arguments for commands. /// The primary scenario for this class is the Zoom command where we /// have multiple menu items and want to fire a single event with an /// argument. We cannot attach an argument value to the native menu /// item so when we do the translation we add it. /// internal class CommandWithArgument { ////// Critical: This can be used to spoof paste command /// [SecurityCritical] public CommandWithArgument(RoutedCommand command) : this(command, null) { } ////// Critical: This can be used to spoof paste command /// [SecurityCritical] public CommandWithArgument(RoutedCommand command, object argument) { _command = new SecurityCriticalDataForSet(command); _argument = argument; } /// /// Critical:This API calls into ExecuteCore and CriticalCanExecute /// [SecurityCritical] public bool Execute(IInputElement target, object argument) { if (argument == null) { argument = _argument; } if (_command.Value == ApplicationCommands.Paste || _command.Value == ApplicationCommands.Copy) { bool unused; if (_command.Value.CriticalCanExecute(argument, target, true, out unused)) { _command.Value.ExecuteCore(argument, target, true); return true; } return false; } if (_command.Value.CanExecute(argument, target)) { _command.Value.Execute(argument, target); return true; } return false; } ////// Critical: This code calls into Routedcommand.QueryStatus /// with a trusted bit, that can be used to cause an elevation. /// [SecurityCritical] public bool QueryEnabled(IInputElement target, object argument) { if (argument == null) { argument = _argument; } if (_command.Value == ApplicationCommands.Paste) { bool unused; return _command.Value.CriticalCanExecute(argument, target, true, out unused); } return _command.Value.CanExecute(argument, target); } public RoutedCommand Command { get { return _command.Value; } } private object _argument; ////// Critical: This data is critical for set since it is used to make a security decision /// private SecurityCriticalDataForSet_command; } #endregion } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // // Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // This is a helper class used for interop to process the // IOleCommandTarget calls in browser hosting scenario // // History: // 06/09/03: kusumav Moved from Application.cs to separate file. // //--------------------------------------------------------------------------- using System; using System.Collections; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows.Threading; using System.Windows; using System.Security; using System.Security.Permissions; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Navigation; using System.Windows.Controls; using MS.Internal.Documents; // DocumentApplicationDocumentViewer using MS.Internal.PresentationFramework; // SecurityHelper using MS.Internal.KnownBoxes; using MS.Win32; namespace MS.Internal.AppModel { #region OleCmdHelper class //// OleCmd helper class for processing IOleCommandTarget calls in browser hosting scenario // internal sealed class OleCmdHelper : MarshalByRefObject, IOleCmdMappingService { internal const int OLECMDERR_E_NOTSUPPORTED = unchecked((int)0x80040100), OLECMDERR_E_DISABLED = unchecked((int)0x80040101), OLECMDERR_E_UNKNOWNGROUP = unchecked((int)0x80040104); internal const uint CommandUnsupported = 0; internal const uint CommandEnabled = (uint)(UnsafeNativeMethods.OLECMDF.OLECMDF_ENABLED | UnsafeNativeMethods.OLECMDF.OLECMDF_SUPPORTED); internal const uint CommandDisabled = (uint)UnsafeNativeMethods.OLECMDF.OLECMDF_SUPPORTED; // IMPORTANT: Keep this in [....] with wcp\host\inc\hostservices.idl internal static readonly Guid CGID_ApplicationCommands = new Guid(0xebbc8a63, 0x8559, 0x4892, 0x97, 0xa8, 0x31, 0xe9, 0xb0, 0xe9, 0x85, 0x91); internal static readonly Guid CGID_EditingCommands = new Guid(0xc77ce45, 0xd1c, 0x4f2a, 0xb2, 0x93, 0xed, 0xd5, 0xe2, 0x7e, 0xba, 0x47); internal OleCmdHelper() { } ////// Critical:This code path enables you to add arbitrary commands /// to a mapping table which is a critical resource /// [SecurityCritical] void IOleCmdMappingService.AddMapping(uint olecmd, RoutedCommand command) { _oleCmdMappingTable.Value[olecmd] = command; } event EventHandler IOleCmdMappingService.UpdatingMappingTable { add { _updateMappingTable += value; } remove { _updateMappingTable -= value; } } ////// Critical: This code calls into _DoqueryStatus /// ////// The native code passes queries here only for the recognized command groups: /// standard (NULL), ApplicaitonCommands, EditingCommands. /// [SecurityCritical] internal void QueryStatus(Guid guidCmdGroup, uint cmdId, ref uint flags) { /***IMPORTANT: Make sure to return allowed and appropriate values according to the specification of IOleCommandTarget::QueryStatus(). In particular: - OLECMDF_SUPPORTED without OLECMDF_ENABLED should not be blindly returned for unrecognized commands. - Some code in IE treats OLECMDERR_E_xxx differently from generic failures. - E_NOTIMPL is not an acceptable return value. */ if (Application.Current == null || Application.IsShuttingDown == true) { Marshal.ThrowExceptionForHR(NativeMethods.E_FAIL); } // Get values from mapping here else mark them as disabled ==> // i.e "supported but not enabled" and is the equivalent of disabled since // there is no explicit "disabled" OLECMD flag IDictionary oleCmdMappingTable = GetOleCmdMappingTable(guidCmdGroup); if (oleCmdMappingTable == null) { Marshal.ThrowExceptionForHR(OleCmdHelper.OLECMDERR_E_UNKNOWNGROUP); } CommandWithArgument command = oleCmdMappingTable[cmdId] as CommandWithArgument; if (command == null) { flags = CommandUnsupported; return; } // Go through the Dispatcher in order to use its SynchronizationContext and also // so that any application exception caused during event routing is reported via // Dispatcher.UnhandledException. // The above code is not in the callback, because it throws, and we don't want the // application to get these exceptions. (The COM Interop layer turns them into HRESULTs.) bool enabled = (bool)Application.Current.Dispatcher.Invoke( DispatcherPriority.Send, new DispatcherOperationCallback(QueryEnabled), command); flags = enabled ? CommandEnabled : CommandDisabled; } ////// Critical: Calls the critical CommandWithArgument.QueryEnabled(). /// [SecurityCritical] private object QueryEnabled(object command) { if (Application.Current.MainWindow == null) return false; IInputElement target = FocusManager.GetFocusedElement(Application.Current.MainWindow); if (target == null) { // This will always succeed because Window is IInputElement target = (IInputElement)Application.Current.MainWindow; } return BooleanBoxes.Box(((CommandWithArgument)command).QueryEnabled(target, null)); } ////// Critical: This code calls into ExecCommandCallback helper /// ////// The native code passes here only commands of the recognized command groups: /// standard (NULL), ApplicaitonCommands, EditingCommands. /// [SecurityCritical] internal void ExecCommand(Guid guidCmdGroup, uint commandId, object arg) { if (Application.Current == null || Application.IsShuttingDown == true) { Marshal.ThrowExceptionForHR(NativeMethods.E_FAIL); } int hresult = (int)Application.Current.Dispatcher.Invoke( DispatcherPriority.Send, new DispatcherOperationCallback(ExecCommandCallback), new object[] { guidCmdGroup, commandId, arg }); // Note: ExecCommandCallback() returns an HRESULT instead of throwing for the reason // explained in QueryStatus(). if(hresult < 0) { Marshal.ThrowExceptionForHR(hresult); } } ////// Critical:This API calls into Execute /// [SecurityCritical] private object ExecCommandCallback(object arguments) { object[] args = (object[])arguments; Invariant.Assert(args.Length == 3); Guid guidCmdGroup = (Guid)args[0]; uint commandId = (uint)args[1]; object arg = args[2]; IDictionary oleCmdMappingTable = GetOleCmdMappingTable(guidCmdGroup); if (oleCmdMappingTable == null) return OLECMDERR_E_UNKNOWNGROUP; CommandWithArgument command = oleCmdMappingTable[commandId] as CommandWithArgument; if (command == null) return OLECMDERR_E_NOTSUPPORTED; if (Application.Current.MainWindow == null) return OLECMDERR_E_DISABLED; IInputElement target = FocusManager.GetFocusedElement(Application.Current.MainWindow); if (target == null) { // This will always succeed because Window is IInputElement target = (IInputElement)Application.Current.MainWindow; } return command.Execute(target, arg) ? NativeMethods.S_OK : OLECMDERR_E_DISABLED; } ////// Critical:This API accesses the commandmapping table and returns it /// TreatAsSafe: It returns a copy which is safe /// [SecurityCritical, SecurityTreatAsSafe] private IDictionary GetOleCmdMappingTable(Guid guidCmdGroup) { IDictionary mappingTable = null; if (guidCmdGroup.Equals(CGID_ApplicationCommands)) { EnsureApplicationCommandsTable(); mappingTable = _applicationCommandsMappingTable.Value; } else if(guidCmdGroup.Equals(Guid.Empty)) { EnsureOleCmdMappingTable(); mappingTable = _oleCmdMappingTable.Value; } else if (guidCmdGroup.Equals(CGID_EditingCommands)) { EnsureEditingCommandsTable(); mappingTable = _editingCommandsMappingTable.Value; } return mappingTable; } ////// Critical: This code initializes the OleCmdMappingTable which is a critical for /// set data structure /// TreatAsSafe: All the values that it adds are predefined handlers in this class /// no external values /// [SecurityCritical,SecurityTreatAsSafe] private void EnsureOleCmdMappingTable() { if (_oleCmdMappingTable.Value == null) { _oleCmdMappingTable.Value = new SortedList(10); //Add applevel commands here _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_SAVE, new CommandWithArgument(ApplicationCommands.Save)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_SAVEAS, new CommandWithArgument(ApplicationCommands.SaveAs)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_PRINT, new CommandWithArgument(ApplicationCommands.Print)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_CUT, new CommandWithArgument(ApplicationCommands.Cut)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_COPY, new CommandWithArgument(ApplicationCommands.Copy)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_PASTE, new CommandWithArgument(ApplicationCommands.Paste)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_PROPERTIES, new CommandWithArgument(ApplicationCommands.Properties)); //Set the Enabled property of Stop and Refresh commands correctly _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_REFRESH, new CommandWithArgument(NavigationCommands.Refresh)); _oleCmdMappingTable.Value.Add((uint)UnsafeNativeMethods.OLECMDID.OLECMDID_STOP, new CommandWithArgument(NavigationCommands.BrowseStop)); //Ensure the mapping table is up-to-date taking into consideration //any navigations that may be changed the input manager (which is currently //per root, so top level navs will require us to reconstruct the table) UpdateMappingTable(_oleCmdMappingTable.Value); } } ////// Critical: This code initializes the OleCmdMappingTable which is a critical for /// set data structure /// TreatAsSafe: All the values that it adds are predefined handlers in this class /// no external values /// [SecurityCritical, SecurityTreatAsSafe] private void EnsureApplicationCommandsTable() { if (_applicationCommandsMappingTable.Value == null) { /* we want to possible add 26 entries, so the capacity should be * 26/0.72 = 19 for default of 1.0 load factor*/ _applicationCommandsMappingTable.Value = new Hashtable(19); //Add applevel commands here // Note: The keys are added as uint type so that the default container comparer works // when we try to look up a command by a uint cmdid. _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Cut, new CommandWithArgument(ApplicationCommands.Cut)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Copy, new CommandWithArgument(ApplicationCommands.Copy)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Paste, new CommandWithArgument(ApplicationCommands.Paste)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_SelectAll, new CommandWithArgument(ApplicationCommands.SelectAll)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Find, new CommandWithArgument(ApplicationCommands.Find)); // Add standard navigation commands _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Refresh, new CommandWithArgument(NavigationCommands.Refresh)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Stop, new CommandWithArgument(NavigationCommands.BrowseStop)); // add document viewer commands _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Digitalsignatures_SignDocument, new CommandWithArgument(DocumentApplicationDocumentViewer.Sign)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Digitalsignatures_RequestSignature, new CommandWithArgument(DocumentApplicationDocumentViewer.RequestSigners)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Digitalsignatures_ViewSignature, new CommandWithArgument(DocumentApplicationDocumentViewer.ShowSignatureSummary)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Permission_Set, new CommandWithArgument(DocumentApplicationDocumentViewer.ShowRMPublishingUI)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Permission_View, new CommandWithArgument(DocumentApplicationDocumentViewer.ShowRMPermissions)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.Edit_Permission_Restrict, new CommandWithArgument(DocumentApplicationDocumentViewer.ShowRMCredentialManager)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_In, new CommandWithArgument(NavigationCommands.IncreaseZoom)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_Out, new CommandWithArgument(NavigationCommands.DecreaseZoom)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_400, new CommandWithArgument(NavigationCommands.Zoom, 400)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_250, new CommandWithArgument(NavigationCommands.Zoom, 250)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_150, new CommandWithArgument(NavigationCommands.Zoom, 150)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_100, new CommandWithArgument(NavigationCommands.Zoom, 100)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_75, new CommandWithArgument(NavigationCommands.Zoom, 75)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_50, new CommandWithArgument(NavigationCommands.Zoom, 50)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_25, new CommandWithArgument(NavigationCommands.Zoom, 25)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_PageWidth, new CommandWithArgument(DocumentViewer.FitToWidthCommand)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_WholePage, new CommandWithArgument(DocumentViewer.FitToHeightCommand)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_TwoPages, new CommandWithArgument(DocumentViewer.FitToMaxPagesAcrossCommand, 2)); _applicationCommandsMappingTable.Value.Add((uint)AppCommands.View_Zoom_Thumbnails, new CommandWithArgument(DocumentViewer.ViewThumbnailsCommand)); //Ensure the mapping table is up-to-date taking into consideration //any navigations that may be changed the input manager (which is currently //per root, so top level navs will require us to reconstruct the table) UpdateMappingTable(_applicationCommandsMappingTable.Value); } } ////// Critical: Initializes _editingCommandsMappingTable, which is a critical for set. /// TreatAsSafe: Only predefined commands are used. EditingCommands are enabled in partial trust. /// [SecurityCritical, SecurityTreatAsSafe] private void EnsureEditingCommandsTable() { if (_editingCommandsMappingTable.Value == null) { _editingCommandsMappingTable.Value = new SortedList(2); // Note: The keys are added as uint type so that the default container comparer works // when we try to look up a command by a uint cmdid. _editingCommandsMappingTable.Value.Add((uint)EditingCommandIds.Backspace, new CommandWithArgument(System.Windows.Documents.EditingCommands.Backspace)); _editingCommandsMappingTable.Value.Add((uint)EditingCommandIds.Delete, new CommandWithArgument(System.Windows.Documents.EditingCommands.Delete)); } } ////// Critical - creates a command binding. Performs an elevation to register the Binding. /// [SecurityCritical] private void UpdateMappingTable(IDictionary mappingTable) { if (_updateMappingTable != null) { _updateMappingTable(this, EventArgs.Empty); } Window window = Application.Current.MainWindow; if (window != null) { window.InputBindings.Add(new KeyBinding(NavigationCommands.Refresh, Key.F5, ModifierKeys.Control)); foreach (CommandWithArgument command in mappingTable.Values) { CommandBinding commandBinding ; // // if this is a secure command - a demand will be performed at // registration of the command binding. // So we perform an assert. // Considered safe - as we're only allowing registration of the command ( e.g. paste) // ISecureCommand secCommand = command.Command as ISecureCommand; if ( secCommand != null ) { secCommand.UserInitiatedPermission.Assert(); } try { commandBinding = new CommandBinding(command.Command); } finally { if (secCommand != null) CodeAccessPermission.RevertAssert(); } if (command.Command == ApplicationCommands.Properties) { commandBinding.CanExecute += new CanExecuteRoutedEventHandler(OnPropertiesQueryEnabled); commandBinding.Executed += new ExecutedRoutedEventHandler(OnPropertiesCommand); } window.CommandBindings.Add(commandBinding); } } } ////// This is the method that gets called when ApplicationCommands.Properties ExecutedRoutedEventHandler get called. /// /// assumptions: /// It should only get called if we are hosted in browser. /// private void OnPropertiesQueryEnabled(object sender, CanExecuteRoutedEventArgs args) { //only hookup the Properties Command if we are hosted in browser and this is a container bool isContainer = Application.Current.MimeType == MimeType.Document; args.CanExecute = (BrowserInteropHelper.IsBrowserHosted && isContainer); } ////// This is the method that gets called when ApplicationCommands.PropertiesCommand /// CommandEventInvokeHandlers get called. /// /// assumptions: /// It should only get called if we are hosted in browser, and if we are /// hosting a container. We do nothing for EXEs /// private void OnPropertiesCommand(object sender, ExecutedRoutedEventArgs execArgs) { // todo: // Task: 40616: MetaData/Properties - View Document Properties // The plan for containers is to wire up a winforms dialog that can // show properties for a package. I recommend having Application // create a method that can be overridden by DocumentApplication // which can respond to this command. The call would look like: // // Application.OnPropertiesCommand(sender, execArgs); // // The Application implementation would do nothing, satisfying xapp. } private SecurityCriticalDataForSet_oleCmdMappingTable; private SecurityCriticalDataForSet _applicationCommandsMappingTable; private SecurityCriticalDataForSet _editingCommandsMappingTable; private EventHandler _updateMappingTable; } #endregion OleCmdHelper class #region IOleCmdMappingService interface internal interface IOleCmdMappingService { void AddMapping(uint olecmd, RoutedCommand command); event EventHandler UpdatingMappingTable; } #endregion IOleCmdMappingService interface #region CommandAndArgument class /// /// This wrapper class helps store default arguments for commands. /// The primary scenario for this class is the Zoom command where we /// have multiple menu items and want to fire a single event with an /// argument. We cannot attach an argument value to the native menu /// item so when we do the translation we add it. /// internal class CommandWithArgument { ////// Critical: This can be used to spoof paste command /// [SecurityCritical] public CommandWithArgument(RoutedCommand command) : this(command, null) { } ////// Critical: This can be used to spoof paste command /// [SecurityCritical] public CommandWithArgument(RoutedCommand command, object argument) { _command = new SecurityCriticalDataForSet(command); _argument = argument; } /// /// Critical:This API calls into ExecuteCore and CriticalCanExecute /// [SecurityCritical] public bool Execute(IInputElement target, object argument) { if (argument == null) { argument = _argument; } if (_command.Value == ApplicationCommands.Paste || _command.Value == ApplicationCommands.Copy) { bool unused; if (_command.Value.CriticalCanExecute(argument, target, true, out unused)) { _command.Value.ExecuteCore(argument, target, true); return true; } return false; } if (_command.Value.CanExecute(argument, target)) { _command.Value.Execute(argument, target); return true; } return false; } ////// Critical: This code calls into Routedcommand.QueryStatus /// with a trusted bit, that can be used to cause an elevation. /// [SecurityCritical] public bool QueryEnabled(IInputElement target, object argument) { if (argument == null) { argument = _argument; } if (_command.Value == ApplicationCommands.Paste) { bool unused; return _command.Value.CriticalCanExecute(argument, target, true, out unused); } return _command.Value.CanExecute(argument, target); } public RoutedCommand Command { get { return _command.Value; } } private object _argument; ////// Critical: This data is critical for set since it is used to make a security decision /// private SecurityCriticalDataForSet_command; } #endregion } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ValidationError.cs
- InputScopeNameConverter.cs
- ListViewDataItem.cs
- TextDocumentView.cs
- CompositeControl.cs
- FileSecurity.cs
- IdleTimeoutMonitor.cs
- DataException.cs
- StyleModeStack.cs
- SQLDecimalStorage.cs
- ZipIOExtraField.cs
- X509ThumbprintKeyIdentifierClause.cs
- AlignmentYValidation.cs
- PropertySegmentSerializationProvider.cs
- SqlBulkCopyColumnMapping.cs
- Emitter.cs
- MimeMapping.cs
- FileDialog.cs
- SimpleTypeResolver.cs
- OdbcConnectionOpen.cs
- FixedElement.cs
- RelationshipConverter.cs
- HwndAppCommandInputProvider.cs
- PerformanceCounterCategory.cs
- Buffer.cs
- Image.cs
- DbProviderConfigurationHandler.cs
- StringUtil.cs
- NetTcpSecurity.cs
- DynamicEntity.cs
- XmlSchemaComplexContentExtension.cs
- ToolboxItemWrapper.cs
- SQLString.cs
- HttpCachePolicyBase.cs
- Size3D.cs
- DiscreteKeyFrames.cs
- XmlSchemaDocumentation.cs
- MasterPageParser.cs
- SqlDelegatedTransaction.cs
- StatusStrip.cs
- TemplatedControlDesigner.cs
- InheritedPropertyChangedEventArgs.cs
- XamlSerializerUtil.cs
- COM2AboutBoxPropertyDescriptor.cs
- Misc.cs
- WebPermission.cs
- InvalidWMPVersionException.cs
- ProbeDuplexCD1AsyncResult.cs
- RandomNumberGenerator.cs
- AssociationType.cs
- BuilderInfo.cs
- ListBoxChrome.cs
- Mapping.cs
- XmlObjectSerializerContext.cs
- OleDbException.cs
- DataGrid.cs
- EdmConstants.cs
- BmpBitmapDecoder.cs
- DrawListViewItemEventArgs.cs
- MaskPropertyEditor.cs
- WebConfigurationManager.cs
- HybridDictionary.cs
- BStrWrapper.cs
- Nullable.cs
- TdsParserStateObject.cs
- PermissionSetEnumerator.cs
- WebPartZoneAutoFormat.cs
- ValidationManager.cs
- FileChangeNotifier.cs
- ButtonBase.cs
- InfiniteTimeSpanConverter.cs
- SizeChangedEventArgs.cs
- DbMetaDataFactory.cs
- ClientConfigurationSystem.cs
- Latin1Encoding.cs
- LogReservationCollection.cs
- DiagnosticsConfigurationHandler.cs
- DialogBaseForm.cs
- DesignerWithHeader.cs
- CompoundFileStreamReference.cs
- ReadingWritingEntityEventArgs.cs
- DescendentsWalkerBase.cs
- ProfileProvider.cs
- EditorPart.cs
- ListControl.cs
- Subtree.cs
- TemplatedMailWebEventProvider.cs
- ISFClipboardData.cs
- ProcessHostFactoryHelper.cs
- PbrsForward.cs
- uribuilder.cs
- HtmlInputCheckBox.cs
- DatePickerAutomationPeer.cs
- AlphaSortedEnumConverter.cs
- ProfilePropertyMetadata.cs
- TrackingMemoryStreamFactory.cs
- Monitor.cs
- XmlReader.cs
- Misc.cs
- Activator.cs