//*****************************************************************************
//
// File: Ribbon.cs
//
// Contents: Class which is used as a façade for the Windows Ribbon
// Framework. In charge of initialization and communication with
// the Windows Ribbon Framework.
//
//*****************************************************************************
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using RibbonLib.Interop;
namespace RibbonLib
{
/// <summary>
/// Main class for using the windows ribbon in a .NET application
/// </summary>
public class Ribbon : IUICommandHandler
{
private IUIImageFromBitmap _imageFromBitmap;
private RibbonUIApplication _application;
private Dictionary<uint, IRibbonControl> _mapRibbonControls = new Dictionary<uint, IRibbonControl>();
private IntPtr _loadedDllHandle = IntPtr.Zero;
private const string DefaultResourceName = "APPLICATION_RIBBON";
/// <summary>
/// Check if ribbon framework has been initialized
/// </summary>
public bool Initalized
{
get
{
return (Framework != null);
}
}
/// <summary>
/// Get ribbon framework object
/// </summary>
public IUIFramework Framework { get; private set; }
/// <summary>
/// Initalize ribbon framework
/// </summary>
/// <param name="form">Form where ribbon should reside</param>
public void InitFramework(IRibbonForm form)
{
string defaultRibbonDllName = GenerateDefaultRibbonDllName();
// if ribbon dll exists, use it
if (File.Exists(defaultRibbonDllName))
{
// load ribbon from ribbon dll resource
InitFramework(form, DefaultResourceName, defaultRibbonDllName);
}
else
{
// load ribbon from executable naive resource
InitFramework(form, DefaultResourceName, Assembly.GetEntryAssembly().GetModules()[0]);
}
}
/// <summary>
/// Initalize ribbon framework
/// </summary>
/// <param name="form">Form where ribbon should reside</param>
/// <param name="resourceName">Identifier of the ribbon resource</param>
/// <param name="resourceModule">Module where to find ribbon resource</param>
public void InitFramework(IRibbonForm form, string resourceName, Module resourceModule)
{
// get main module HINSTANCE
IntPtr hInstance = Marshal.GetHINSTANCE(resourceModule);
InitFramework(form, resourceName, hInstance);
}
/// <summary>
/// Initalize ribbon framework
/// </summary>
/// <param name="form">Form where ribbon should reside</param>
/// <param name="resourceName">Identifier of the ribbon resource</param>
/// <param name="ribbonDllName">Dll name where to find ribbon resource</param>
public void InitFramework(IRibbonForm form, string resourceName, string ribbonDllName)
{
// dynamically load ribbon library
_loadedDllHandle = NativeMethods.LoadLibraryEx(ribbonDllName, IntPtr.Zero,
NativeMethods.DONT_RESOLVE_DLL_REFERENCES |
NativeMethods.LOAD_IGNORE_CODE_AUTHZ_LEVEL |
NativeMethods.LOAD_LIBRARY_AS_DATAFILE |
NativeMethods.LOAD_LIBRARY_AS_IMAGE_RESOURCE);
InitFramework(form, resourceName, _loadedDllHandle);
}
/// <summary>
/// Initalize ribbon framework
/// </summary>
/// <param name="form">Form where ribbon should reside</param>
/// <param name="resourceName">Identifier of the ribbon resource</param>
/// <param name="hInstance">Pointer to HINSTANCE of module where we can find ribbon resource</param>
public void InitFramework(IRibbonForm form, string resourceName, IntPtr hInstance)
{
// create ribbon framework object
Framework = CreateRibbonFramework();
_imageFromBitmap = CreateImageFromBitmapFactory();
// create ribbon application object
_application = new RibbonUIApplication(this, form);
// init ribbon framework
HRESULT hr = Framework.Initialize(form.WindowHandle, _application);
if (NativeMethods.Failed(hr))
{
Marshal.ThrowExceptionForHR((int)hr);
}
// load ribbon ui
hr = Framework.LoadUI(hInstance, resourceName);
if (NativeMethods.Failed(hr))
{
Marshal.ThrowExceptionForHR((int)hr);
}
}
/// <summary>
/// Destroy ribbon framework
/// </summary>
public void DestroyFramework()
{
if (Initalized)
{
// destroy ribbon framework
Framework.Destroy();
Marshal.ReleaseComObject(Framework);
// remove reference to framework object
Framework = null;
}
if (_loadedDllHandle != IntPtr.Zero)
{
// free dynamic library
NativeMethods.FreeLibrary(_loadedDllHandle);
_loadedDllHandle = IntPtr.Zero;
}
if (_imageFromBitmap != null)
{
// remove reference to imageFromBitmap object
_imageFromBitmap = null;
}
if (_application != null)
{
// remove reference to application object
_application = null;
}
// remove references to ribbon controls
_mapRibbonControls.Clear();
}
/// <summary>
/// Change ribbon background, highlight and text colors
/// </summary>
/// <param name="background">new background color</param>
/// <param name="highlight">new highlight color</param>
/// <param name="text">new text color</param>
public void SetColors(Color background, Color highlight, Color text)
{
if (!Initalized)
{
return;
}
// convert colors to proper color format
uint backgroundColor = ColorHelper.HSB2Uint(ColorHelper.HSL2HSB(ColorHelper.RGB2HSL(background)));
uint highlightColor = ColorHelper.HSB2Uint(ColorHelper.HSL2HSB(ColorHelper.RGB2HSL(highlight)));
uint textColor = ColorHelper.HSB2Uint(ColorHelper.HSL2HSB(ColorHelper.RGB2HSL(text)));
IPropertyStore propertyStore = (IPropertyStore)Framework;
PropVariant backgroundColorProp = PropVariant.FromObject(backgroundColor);
PropVariant highlightColorProp = PropVariant.FromObject(highlightColor);
PropVariant textColorProp = PropVariant.FromObject(textColor);
// set ribbon colors
propertyStore.SetValue(ref RibbonProperties.GlobalBackgroundColor, ref backgroundColorProp);
propertyStore.SetValue(ref RibbonProperties.GlobalHighlightColor, ref highlightColorProp);
propertyStore.SetValue(ref RibbonProperties.GlobalTextColor, ref textColorProp);
propertyStore.Commit();
}
/// <summary>
/// Wraps a bitmap object with IUIImage interface
/// </summary>
/// <param name="bitmap">bitmap object to wrap</param>
/// <returns>IUIImage wrapper</returns>
public IUIImage ConvertToUIImage(Bitmap bitmap)
{
if (_imageFromBitmap == null)
{
return null;
}
IUIImage uiImage;
_imageFromBitmap.CreateImage(bitmap.GetHbitmap(), Ownership.Transfer, out uiImage);
return uiImage;
}
/// <summary>
/// Set current application modes
/// </summary>
/// <param name="modesArray">array of modes to set</param>
/// <remarks>Unlisted modes will be unset</remarks>
public void SetModes(params byte[] modesArray)
{
// check that ribbon is initialized
if (!Initalized)
{
return;
}
// calculate compact modes value
int compactModes = 0;
for (int i = 0; i < modesArray.Length; ++i)
{
if (modesArray[i] >= 32)
{
throw new ArgumentException("Modes should range between 0 to 31.");
}
compactModes |= (1 << modesArray[i]);
}
// set modes
Framework.SetModes(compactModes);
}
/// <summary>
/// Shows a predefined context popup in a specific location
/// </summary>
/// <param name="contextPopupID">commandId for the context popup</param>
/// <param name="x">X in screen coordinates</param>
/// <param name="y">Y in screen coordinates</param>
public void ShowContextPopup(uint contextPopupID, int x, int y)
{
// check that ribbon is initialized
if (!Initalized)
{
return;
}
object contextualUIObject;
Guid contextualUIGuid = new Guid(RibbonIIDGuid.IUIContextualUI);
HRESULT hr = Framework.GetView(contextPopupID, ref contextualUIGuid, out contextualUIObject);
if (NativeMethods.Succeeded(hr))
{
IUIContextualUI contextualUI = contextualUIObject as IUIContextualUI;
contextualUI.ShowAtLocation(x, y);
Marshal.ReleaseComObject(contextualUI);
}
else
{
Marshal.ThrowExceptionForHR((int)hr);
}
}
/// <summary>
/// Specifies whether the ribbon is in a collapsed or expanded state
/// </summary>
public bool Minimized
{
get
{
// check that ribbon is initialized
if (!Initalized)
{
return false;
}
IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
PropVariant propMinimized;
HRESULT hr = propertyStore.GetValue(ref RibbonProperties.Minimized, out propMinimized);
return (bool)propMinimized.Value;
}
set
{
// check that ribbon is initialized
if (!Initalized)
{
return;
}
IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
PropVariant propMinimized = PropVariant.FromObject(value);
HRESULT hr = propertyStore.SetValue(ref RibbonProperties.Minimized, ref propMinimized);
hr = propertyStore.Commit();
}
}
/// <summary>
/// Specifies whether the ribbon user interface (UI) is in a visible or hidden state
/// </summary>
public bool Viewable
{
get
{
// check that ribbon is initialized
if (!Initalized)
{
return false;
}
IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
PropVariant propViewable;
HRESULT hr = propertyStore.GetValue(ref RibbonProperties.Viewable, out propViewable);
return (bool)propViewable.Value;
}
set
{
// check that ribbon is initialized
if (!Initalized)
{
return;
}
IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
PropVariant propViewable = PropVariant.FromObject(value);
HRESULT hr = propertyStore.SetValue(ref RibbonProperties.Viewable, ref propViewable);
hr = propertyStore.Commit();
}
}
/// <summary>
/// Specifies whether the quick access toolbar is docked at the top or at the bottom
/// </summary>
public ControlDock QuickAccessToolbarDock
{
get
{
// check that ribbon is initialized
if (!Initalized)
{
return ControlDock.Top;
}
IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
PropVariant propQuickAccessToolbarDock;
HRESULT hr = propertyStore.GetValue(ref RibbonProperties.QuickAccessToolbarDock, out propQuickAccessToolbarDock);
return (ControlDock)(uint)propQuickAccessToolbarDock.Value;
}
set
{
// check that ribbon is initialized
if (!Initalized)
{
return;
}
IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
PropVariant propQuickAccessToolbarDock = PropVariant.FromObject((uint)value);
HRESULT hr = propertyStore.SetValue(ref RibbonProperties.QuickAccessToolbarDock, ref propQuickAccessToolbarDock);
hr = propertyStore.Commit();
}
}
public void SaveSettingsToStream(Stream stream)
{
if (!Initalized)
{
return;
}
StreamAdapter streamAdapter = new StreamAdapter(stream);
HRESULT hr = _application.UIRibbon.SaveSettingsToStream(streamAdapter);
}
public void LoadSettingsFromStream(Stream stream)
{
if (!Initalized)
{
return;
}
StreamAdapter streamAdapter = new StreamAdapter(stream);
HRESULT hr = _application.UIRibbon.LoadSettingsFromStream(streamAdapter);
}
/// <summary>
/// Create ribbon framework object
/// </summary>
/// <returns>ribbon framework object</returns>
private static IUIFramework CreateRibbonFramework()
{
try
{
return new UIRibbonFramework() as IUIFramework;
}
catch (COMException exception)
{
throw new PlatformNotSupportedException("The ribbon framework couldn't be found on this system.", exception);
}
}
/// <summary>
/// Create image-from-bitmap factory object
/// </summary>
/// <returns>image-from-bitmap factory object</returns>
private static IUIImageFromBitmap CreateImageFromBitmapFactory()
{
return new UIRibbonImageFromBitmapFactory() as IUIImageFromBitmap;
}
/// <summary>
/// Generates a default ribbon dll name
/// </summary>
/// <returns>name of the dll</returns>
private string GenerateDefaultRibbonDllName()
{
return Path.ChangeExtension(new Uri(Assembly.GetEntryAssembly().CodeBase).LocalPath, ".ribbon.dll");
}
/// <summary>
/// Adds a ribbon control to the internal map
/// </summary>
/// <param name="ribbonControl">ribbon control to add</param>
internal void AddRibbonControl(IRibbonControl ribbonControl)
{
_mapRibbonControls.Add(ribbonControl.CommandID, ribbonControl);
}
#region Implementation of IUICommandHandler
/// <summary>
/// Implementation of IUICommandHandler.Execute
/// Responds to execute events on Commands bound to the Command handler
/// </summary>
/// <param name="commandID">the command that has been executed</param>
/// <param name="verb">the mode of execution</param>
/// <param name="key">the property that has changed</param>
/// <param name="currentValue">the new value of the property that has changed</param>
/// <param name="commandExecutionProperties">additional data for this execution</param>
/// <returns>Returns S_OK if successful, or an error value otherwise</returns>
/// <remarks>This method is used internally by the Ribbon class and should not be called by the user.</remarks>
public virtual HRESULT Execute(uint commandID, ExecutionVerb verb, PropertyKeyRef key, PropVariantRef currentValue, IUISimplePropertySet commandExecutionProperties)
{
#if DEBUG
Debug.WriteLine(string.Format("Execute verb: {0} for command {1}", verb, commandID));
#endif
if (_mapRibbonControls.ContainsKey(commandID))
{
return _mapRibbonControls[commandID].Execute(verb, key, currentValue, commandExecutionProperties);
}
return HRESULT.S_OK;
}
/// <summary>
/// Implementation of IUICommandHandler.UpdateProperty
/// Responds to property update requests from the Windows Ribbon (Ribbon) framework.
/// </summary>
/// <param name="commandID">The ID for the Command, which is specified in the Markup resource file</param>
/// <param name="key">The Property Key to update</param>
/// <param name="currentValue">A pointer to the current value for key. This parameter can be NULL</param>
/// <param name="newValue">When this method returns, contains a pointer to the new value for key</param>
/// <returns>Returns S_OK if successful, or an error value otherwise</returns>
/// <remarks>This method is used internally by the Ribbon class and should not be called by the user.</remarks>
public virtual HRESULT UpdateProperty(uint commandID, ref PropertyKey key, PropVariantRef currentValue, ref PropVariant newValue)
{
#if DEBUG
Debug.WriteLine(string.Format("UpdateProperty key: {0} for command {1}", RibbonProperties.GetPropertyKeyName(ref key), commandID));
#endif
if (_mapRibbonControls.ContainsKey(commandID))
{
return _mapRibbonControls[commandID].UpdateProperty(ref key, currentValue, ref newValue);
}
return HRESULT.S_OK;
}
#endregion
}
}