C# Winform WPF DeskBand 窗体嵌入任务栏,在任务栏显示文字
原文:C# Winform WPF DeskBand 窗体嵌入任务栏,在任务栏显示文字

最近写了个小程序,用于将固态硬盘的写入量等信息显示在任务栏,最开始使用Windows API也可以实现,但是当任务栏托盘增加的时候,会被遮盖,最终采用了DeskBand来实现,填了很多坑。

参考的GitHub地址:https://github.com/dsafa/CSDeskBand

DeskBand相关代码如下:

COLORREF:

// This code snippet was used by SharpShell.
//

using System.Drawing;
using System.Runtime.InteropServices;namespace MyDiskInfo.Interop
{[StructLayout(LayoutKind.Sequential)]public struct COLORREF{public COLORREF(Color color){Dword = (uint)color.R + (((uint)color.G) << 8) + (((uint)color.B) << 16);}public uint Dword;public Color Color{get{return Color.FromArgb((int)(0x000000FFU & Dword),(int)(0x0000FF00U & Dword) >> 8,(int)(0x00FF0000U & Dword) >> 16);}}}
}

View Code

DESKBANDINFO:

using System;
using System.Runtime.InteropServices;namespace MyDiskInfo.Interop
{/// <summary>/// Receives information about a band object. This structure is used with the deprecated IDeskBand::GetBandInfo method./// </summary>[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]public struct DESKBANDINFO{/// <summary>/// Set of flags that determine which members of this structure are being requested. /// </summary>/// <remarks>/// This will be a combination of the following values:///     DBIM_MINSIZE    ptMinSize is being requested.///     DBIM_MAXSIZE    ptMaxSize is being requested.///     DBIM_INTEGRAL   ptIntegral is being requested.///     DBIM_ACTUAL     ptActual is being requested.///     DBIM_TITLE      wszTitle is being requested.///     DBIM_MODEFLAGS  dwModeFlags is being requested.///     DBIM_BKCOLOR    crBkgnd is being requested./// </remarks>public DBIM dwMask;/// <summary>/// Point structure that receives the minimum size of the band object. /// The minimum width is placed in the x member and the minimum height /// is placed in the y member. /// </summary>public POINT ptMinSize;/// <summary>/// Point structure that receives the maximum size of the band object. /// The maximum height is placed in the y member and the x member is ignored. /// If there is no limit for the maximum height, (LONG)-1 should be used. /// </summary>public POINT ptMaxSize;/// <summary>/// Point structure that receives the sizing step value of the band object. /// The vertical step value is placed in the y member, and the x member is ignored. /// The step value determines in what increments the band will be resized. /// </summary>/// <remarks>/// This member is ignored if dwModeFlags does not contain DBIMF_VARIABLEHEIGHT. /// </remarks>public POINT ptIntegral;/// <summary>/// Point structure that receives the ideal size of the band object. /// The ideal width is placed in the x member and the ideal height is placed in the y member. /// The band container will attempt to use these values, but the band is not guaranteed to be this size./// </summary>public POINT ptActual;/// <summary>/// The title of the band./// </summary>[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]public String wszTitle;/// <summary>/// A value that receives a set of flags that define the mode of operation for the band object. /// </summary>/// <remarks>/// This must be one or a combination of the following values.///     DBIMF_NORMAL///     The band is normal in all respects. The other mode flags modify this flag.///     DBIMF_VARIABLEHEIGHT///     The height of the band object can be changed. The ptIntegral member defines the ///     step value by which the band object can be resized. ///     DBIMF_DEBOSSED///     The band object is displayed with a sunken appearance.///     DBIMF_BKCOLOR///     The band will be displayed with the background color specified in crBkgnd./// </remarks>public DBIMF dwModeFlags;/// <summary>/// The background color of the band./// </summary>/// <remarks>/// This member is ignored if dwModeFlags does not contain the DBIMF_BKCOLOR flag. /// </remarks>public COLORREF crBkgnd;/// <summary>/// The view mode of the band object. This is one of the following values./// </summary>
        [Flags]public enum DBIF{/// <summary>/// Band object is displayed in a horizontal band./// </summary>DBIF_VIEWMODE_NORMAL = 0x0000,/// <summary>/// Band object is displayed in a vertical band./// </summary>DBIF_VIEWMODE_VERTICAL = 0x0001,/// <summary>/// Band object is displayed in a floating band./// </summary>DBIF_VIEWMODE_FLOATING = 0x0002,/// <summary>/// Band object is displayed in a transparent band./// </summary>DBIF_VIEWMODE_TRANSPARENT = 0x0004}/// <summary>/// The set of flags that determine which members of this structure are being requested by the caller. One or more of the following values:/// </summary>
        [Flags]public enum DBIM{/// <summary>/// ptMinSize is requested./// </summary>DBIM_MINSIZE = 0x0001,/// <summary>/// ptMaxSize is requested./// </summary>DBIM_MAXSIZE = 0x0002,/// <summary>/// ptIntegral is requested./// </summary>DBIM_INTEGRAL = 0x0004,/// <summary>/// ptActual is requested./// </summary>DBIM_ACTUAL = 0x0008,/// <summary>/// wszTitle is requested./// </summary>DBIM_TITLE = 0x0010,/// <summary>/// dwModeFlags is requested./// </summary>DBIM_MODEFLAGS = 0x0020,/// <summary>/// crBkgnd is requested./// </summary>DBIM_BKCOLOR = 0x0040}/// <summary>/// A value that receives a set of flags that specify the mode of operation for the band object. One or more of the following values:/// </summary>
        [Flags]public enum DBIMF : uint{/// <summary>/// The band uses default properties. The other mode flags modify this flag./// </summary>DBIMF_NORMAL = 0x0000,/// <summary>/// Windows XP and later: The band object is of a fixed sized and position. With this flag, a sizing grip is not displayed on the band object./// </summary>DBIMF_FIXED = 0x0001,/// <summary>/// DBIMF_FIXEDBMP/// Windows XP and later: The band object uses a fixed bitmap (.bmp) file as its background. Note that backgrounds are not supported in all cases, so the bitmap may not be seen even when this flag is set./// </summary>DBIMF_FIXEDBMP = 0x0004,/// <summary>/// The height of the band object can be changed. The ptIntegral member defines the step value by which the band object can be resized./// </summary>DBIMF_VARIABLEHEIGHT = 0x0008,/// <summary>/// Windows XP and later: The band object cannot be removed from the band container./// </summary>DBIMF_UNDELETEABLE = 0x0010,/// <summary>/// The band object is displayed with a sunken appearance./// </summary>DBIMF_DEBOSSED = 0x0020,/// <summary>/// The band is displayed with the background color specified in crBkgnd./// </summary>DBIMF_BKCOLOR = 0x0040,/// <summary>/// Windows XP and later: If the full band object cannot be displayed (that is, the band object is smaller than ptActual, a chevron is shown to indicate that there are more options available. These options are displayed when the chevron is clicked./// </summary>DBIMF_USECHEVRON = 0x0080,/// <summary>/// Windows XP and later: The band object is displayed in a new row in the band container./// </summary>DBIMF_BREAK = 0x0100,/// <summary>/// Windows XP and later: The band object is the first object in the band container./// </summary>DBIMF_ADDTOFRONT = 0x0200,/// <summary>/// Windows XP and later: The band object is displayed in the top row of the band container./// </summary>DBIMF_TOPALIGN = 0x0400,/// <summary>/// Windows Vista and later: No sizing grip is ever displayed to allow the user to move or resize the band object./// </summary>DBIMF_NOGRIPPER = 0x0800,/// <summary>/// Windows Vista and later: A sizing grip that allows the user to move or resize the band object is always shown, even if that band object is the only one in the container./// </summary>DBIMF_ALWAYSGRIPPER = 0x1000,/// <summary>/// Windows Vista and later: The band object should not display margins./// </summary>DBIMF_NOMARGINS = 0x2000}}
}

View Code

POINT:

// This code snippet was used by SharpShell.
//
using System.Runtime.InteropServices;namespace MyDiskInfo.Interop
{/// <summary>/// The POINT structure defines the x- and y- coordinates of a point./// </summary>[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]public struct POINT{/// <summary>/// The x-coordinate of the point./// </summary>public int X;/// <summary>/// The y-coordinate of the point./// </summary>public int Y;}
}

View Code

RECT:

using System.Runtime.InteropServices;namespace MyDiskInfo.Interop
{[StructLayout(LayoutKind.Sequential)]public struct RECT{public RECT(int left, int top, int right, int bottom){this.left = left;this.top = top;this.right = right;this.bottom = bottom;}public int left, top, right, bottom;public int Width(){return right - left;}public int Height(){return bottom - top;}public void Offset(int x, int y){left += x;right += x;top += y;bottom += y;}public void Set(int left, int top, int right, int bottom){this.left = left;this.top = top;this.right = right;this.bottom = bottom;}public bool IsEmpty(){return Width() == 0 && Height() == 0;}}
}

View Code

Attributes:

using System;
using System.Runtime.InteropServices;namespace MyDiskInfo
{/// <summary>/// The display name of the extension and the description for the HelpText(displayed in status bar when menu command selected)./// </summary>
    [AttributeUsage(AttributeTargets.Class)]public class DeskBandInfoAttribute : System.Attribute{private string _displayName;private string _helpText;public string DisplayName{get { return _displayName; }}public string HelpText{get { return _helpText; }}public DeskBandInfoAttribute() { }public DeskBandInfoAttribute(string displayName, string helpText){_displayName = displayName;_helpText = helpText;}}
}

View Code

ComImport:

using System;
using System.Runtime.InteropServices;namespace MyDiskInfo.Interop
{/// <summary>/// Provides a simple way to support communication between an object and its site in the container./// </summary>
    [ComImport][InterfaceType(ComInterfaceType.InterfaceIsIUnknown)][Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")]public interface IObjectWithSite{/// <summary>/// Enables a container to pass an object a pointer to the interface for its site./// </summary>/// <param name="pUnkSite">A pointer to the IUnknown interface pointer of the site managing this object./// If NULL, the object should call Release on any existing site at which point the object no longer knows its site.</param>void SetSite([In, MarshalAs(UnmanagedType.IUnknown)] Object pUnkSite);/// <summary>/// Retrieves the latest site passed using SetSite./// </summary>/// <param name="riid">The IID of the interface pointer that should be returned in ppvSite.</param>/// <param name="ppvSite">Address of pointer variable that receives the interface pointer requested in riid.</param>void GetSite(ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out Object ppvSite);}/// <summary>/// Exposes a method that is used to communicate focus changes for a user input object contained in the Shell./// </summary>
    [ComImport][InterfaceType(ComInterfaceType.InterfaceIsIUnknown)][Guid("F1DB8392-7331-11D0-8C99-00A0C92DBFE8")]public interface IInputObjectSite{/// <summary>/// Informs the browser that the focus has changed./// </summary>/// <param name="punkObj">The address of the IUnknown interface of the object gaining or losing the focus.</param>/// <param name="fSetFocus">Indicates if the object has gained or lost the focus. If this value is nonzero, the object has gained the focus./// If this value is zero, the object has lost the focus.</param>/// <returns>Returns S_OK if the method was successful, or a COM-defined error code otherwise.</returns>
        [PreserveSig]Int32 OnFocusChangeIS([MarshalAs(UnmanagedType.IUnknown)] Object punkObj, Int32 fSetFocus);}/// <summary>/// The IOleWindow interface provides methods that allow an application to obtain the handle to the various windows that participate in in-place activation, and also to enter and exit context-sensitive help mode./// </summary>
    [ComImport][InterfaceType(ComInterfaceType.InterfaceIsIUnknown)][Guid("00000114-0000-0000-C000-000000000046")]public interface IOleWindow{/// <summary>/// Retrieves a handle to one of the windows participating in in-place activation (frame, document, parent, or in-place object window)./// </summary>/// <param name="phwnd">A pointer to a variable that receives the window handle.</param>/// <returns>This method returns S_OK on success.</returns>
        [PreserveSig]int GetWindow(out IntPtr phwnd);/// <summary>/// Determines whether context-sensitive help mode should be entered during an in-place activation session./// </summary>/// <param name="fEnterMode">TRUE if help mode should be entered; FALSE if it should be exited.</param>/// <returns>This method returns S_OK if the help mode was entered or exited successfully, depending on the value passed in fEnterMode.</returns>
        [PreserveSig]int ContextSensitiveHelp(bool fEnterMode);}[ComImport][InterfaceType(ComInterfaceType.InterfaceIsIUnknown)][Guid("012DD920-7B26-11D0-8CA9-00A0C92DBFE8")]public interface IDockingWindow : IOleWindow{#region IOleWindow[PreserveSig]new int GetWindow(out IntPtr phwnd);[PreserveSig]new int ContextSensitiveHelp(bool fEnterMode);#endregion/// <summary>/// Instructs the docking window object to show or hide itself./// </summary>/// <param name="fShow">TRUE if the docking window object should show its window./// FALSE if the docking window object should hide its window and return its border space by calling SetBorderSpaceDW with zero values.</param>/// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
        [PreserveSig]int ShowDW([In] bool fShow);/// <summary>/// Notifies the docking window object that it is about to be removed from the frame./// The docking window object should save any persistent information at this time./// </summary>/// <param name="dwReserved">Reserved. This parameter should always be zero.</param>/// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
        [PreserveSig]int CloseDW([In] UInt32 dwReserved);/// <summary>/// Notifies the docking window object that the frame's border space has changed./// </summary>/// <param name="prcBorder">Pointer to a RECT structure that contains the frame's available border space.</param>/// <param name="punkToolbarSite">Pointer to the site's IUnknown interface. The docking window object should call the QueryInterface method for this interface, requesting IID_IDockingWindowSite./// The docking window object then uses that interface to negotiate its border space. It is the docking window object's responsibility to release this interface when it is no longer needed.</param>/// <param name="fReserved">Reserved. This parameter should always be zero.</param>/// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
        [PreserveSig]int ResizeBorderDW(RECT prcBorder, [In, MarshalAs(UnmanagedType.IUnknown)] IntPtr punkToolbarSite, bool fReserved);}/// <summary>/// Gets information about a band object./// </summary>
    [ComImport][InterfaceType(ComInterfaceType.InterfaceIsIUnknown)][Guid("EB0FE172-1A3A-11D0-89B3-00A0C90A90AC")]public interface IDeskBand : IDockingWindow{#region IOleWindow[PreserveSig]new int GetWindow(out IntPtr phwnd);[PreserveSig]new int ContextSensitiveHelp(bool fEnterMode);#endregion#region IDockingWindow[PreserveSig]new int ShowDW([In] bool fShow);[PreserveSig]new int CloseDW([In] UInt32 dwReserved);[PreserveSig]new int ResizeBorderDW(RECT prcBorder, [In, MarshalAs(UnmanagedType.IUnknown)] IntPtr punkToolbarSite, bool fReserved);#endregion/// <summary>/// Gets state information for a band object./// </summary>/// <param name="dwBandID">The identifier of the band, assigned by the container. The band object can retain this value if it is required.</param>/// <param name="dwViewMode">The view mode of the band object. One of the following values: DBIF_VIEWMODE_NORMAL, DBIF_VIEWMODE_VERTICAL, DBIF_VIEWMODE_FLOATING, DBIF_VIEWMODE_TRANSPARENT.</param>/// <param name="pdbi">Pointer to a DESKBANDINFO structure that receives the band information for the object. The dwMask member of this structure indicates the specific information that is being requested.</param>/// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
        [PreserveSig]int GetBandInfo(UInt32 dwBandID, DESKBANDINFO.DBIF dwViewMode, ref DESKBANDINFO pdbi);}/// <summary>/// Exposes methods to enable and query translucency effects in a deskband object./// </summary>
    [ComImport][InterfaceType(ComInterfaceType.InterfaceIsIUnknown)][Guid("79D16DE4-ABEE-4021-8D9D-9169B261D657")]public interface IDeskBand2 : IDeskBand{#region IOleWindow[PreserveSig]new int GetWindow(out IntPtr phwnd);[PreserveSig]new int ContextSensitiveHelp(bool fEnterMode);#endregion#region IDockingWindow[PreserveSig]new int ShowDW([In] bool fShow);[PreserveSig]new int CloseDW([In] UInt32 dwReserved);[PreserveSig]new int ResizeBorderDW(RECT prcBorder, [In, MarshalAs(UnmanagedType.IUnknown)] IntPtr punkToolbarSite, bool fReserved);#endregion#region IDeskBand[PreserveSig]new int GetBandInfo(UInt32 dwBandID, DESKBANDINFO.DBIF dwViewMode, ref DESKBANDINFO pdbi);#endregion/// <summary>/// Indicates the deskband's ability to be displayed as translucent./// </summary>/// <param name="pfCanRenderComposited">When this method returns, contains a BOOL indicating ability.</param>/// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
        [PreserveSig]int CanRenderComposited(out bool pfCanRenderComposited);/// <summary>/// Sets the composition state./// </summary>/// <param name="fCompositionEnabled">TRUE to enable the composition state; otherwise, FALSE.</param>/// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
        [PreserveSig]int SetCompositionState(bool fCompositionEnabled);/// <summary>/// Gets the composition state./// </summary>/// <param name="pfCompositionEnabled">When this method returns, contains a BOOL that indicates state.</param>/// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
        [PreserveSig]int GetCompositionState(out bool pfCompositionEnabled);}
}

View Code

DeskBand,这里和GitHub上的程序不同的是,DeskBand直接继承的ElementHost类,GitHub上的好像是多例的,我想要的是单例的,所以修改了一下。这里粘的代码是WPF的,如果你想实现Winform的,就让DeskBand继承UserControl,DeskBand代码如下:

// Copyright(c) 2017 Patrick Becker
//
// Visit the Project page for more information.
// https://github.com/patbec/TaskbarSampleExtensionusing Microsoft.Win32;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using MyDiskInfo.Interop;
using System.Windows.Forms.Integration;namespace MyDiskInfo
{/// <summary>/// Basic class for a DeskBand object/// </summary>/// <example>/// [ComVisible(true)]/// [Guid("00000000-0000-0000-0000-000000000000")]/// [DeskBandInfo("Beispiel Erweiterung", "Diese ist eine Beispiel Erweiterung für die Taskleiste.")]/// public class SampleExtension : DeskBand/// { /*...*/ }/// </example>public class DeskBand : ElementHost, IObjectWithSite, IDeskBand2{private const int S_OK = 0;private const int E_NOTIMPL = unchecked((int)0x80004001);protected IInputObjectSite DeskBandSite;public DeskBand(){InitializeComponent();}private void InitializeComponent(){this.Name = "DeskBand";}#region Properties/// <summary>/// Title of the band object, displayed by default on the left or top of the object./// </summary>[Browsable(true)][DefaultValue("")]public String Title { get; set; }/// <summary>/// Minimum size of the band object. Default value of -1 sets no minimum constraint./// </summary>[Browsable(true)][DefaultValue(typeof(Size), "-1,-1")]public Size MinSize { get; set; }/// <summary>/// Maximum size of the band object. Default value of -1 sets no maximum constraint./// </summary>[Browsable(true)][DefaultValue(typeof(Size), "-1,-1")]public Size MaxSize { get; set; }/// <summary>/// Minimum vertical size of the band object. Default value of -1 sets no maximum constraint. (Used when the taskbar is aligned vertically.)/// </summary>[Browsable(true)][DefaultValue(typeof(Size), "-1,-1")]public Size MinSizeVertical { get; set; }/// <summary>/// Says that band object's size must be multiple of this size. Defauilt value of -1 does not set this constraint./// </summary>[Browsable(true)][DefaultValue(typeof(Size), "-1,-1")]public Size IntegralSize { get; set; }#endregion#region IObjectWithSitepublic void SetSite([In, MarshalAs(UnmanagedType.IUnknown)] Object pUnkSite){if (DeskBandSite != null)Marshal.ReleaseComObject(DeskBandSite);DeskBandSite = (IInputObjectSite)pUnkSite;}public void GetSite(ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out Object ppvSite){ppvSite = DeskBandSite;}#endregion#region IDeskBand2public virtual int CanRenderComposited(out bool pfCanRenderComposited){pfCanRenderComposited = true;return S_OK;}public int SetCompositionState(bool fCompositionEnabled){fCompositionEnabled = true;return S_OK;}public int GetCompositionState(out bool pfCompositionEnabled){pfCompositionEnabled = false;return S_OK;}public int GetBandInfo(uint dwBandID, DESKBANDINFO.DBIF dwViewMode, ref DESKBANDINFO pdbi){if (pdbi.dwMask.HasFlag(DESKBANDINFO.DBIM.DBIM_MINSIZE)){// Support for a vertical taskbar// Most examples have no support for a vertical taskbar. Who in hell uses their taskbar vertically? Me! Very practical on a 21:9 monitor.if (dwViewMode.HasFlag(DESKBANDINFO.DBIF.DBIF_VIEWMODE_FLOATING) || dwViewMode.HasFlag(DESKBANDINFO.DBIF.DBIF_VIEWMODE_VERTICAL)){pdbi.ptMinSize.Y = this.MinSizeVertical.Width;pdbi.ptMinSize.X = this.MinSizeVertical.Height;}else{pdbi.ptMinSize.X = this.MinSize.Width;pdbi.ptMinSize.Y = this.MinSize.Height;}}if (pdbi.dwMask.HasFlag(DESKBANDINFO.DBIM.DBIM_MAXSIZE)){if (dwViewMode.HasFlag(DESKBANDINFO.DBIF.DBIF_VIEWMODE_FLOATING) || dwViewMode.HasFlag(DESKBANDINFO.DBIF.DBIF_VIEWMODE_VERTICAL)){pdbi.ptMaxSize.Y = this.MaxSize.Width;pdbi.ptMaxSize.X = this.MaxSize.Height;}else{pdbi.ptMaxSize.X = this.MaxSize.Width;pdbi.ptMaxSize.Y = this.MaxSize.Height;}}if (pdbi.dwMask.HasFlag(DESKBANDINFO.DBIM.DBIM_INTEGRAL)){if (dwViewMode.HasFlag(DESKBANDINFO.DBIF.DBIF_VIEWMODE_FLOATING) || dwViewMode.HasFlag(DESKBANDINFO.DBIF.DBIF_VIEWMODE_VERTICAL)){pdbi.ptIntegral.Y = this.IntegralSize.Width;pdbi.ptIntegral.X = this.IntegralSize.Height;}else{pdbi.ptIntegral.X = this.IntegralSize.Width;pdbi.ptIntegral.Y = this.IntegralSize.Height;}}if (pdbi.dwMask.HasFlag(DESKBANDINFO.DBIM.DBIM_ACTUAL)){if (dwViewMode.HasFlag(DESKBANDINFO.DBIF.DBIF_VIEWMODE_FLOATING) || dwViewMode.HasFlag(DESKBANDINFO.DBIF.DBIF_VIEWMODE_VERTICAL)){pdbi.ptActual.Y = this.Size.Width;pdbi.ptActual.X = this.Size.Height;}else{pdbi.ptActual.X = this.Size.Width;pdbi.ptActual.Y = this.Size.Height;}}if (pdbi.dwMask.HasFlag(DESKBANDINFO.DBIM.DBIM_TITLE)){pdbi.wszTitle = this.Title;}pdbi.dwModeFlags = DESKBANDINFO.DBIMF.DBIMF_ALWAYSGRIPPER | DESKBANDINFO.DBIMF.DBIMF_NORMAL | DESKBANDINFO.DBIMF.DBIMF_VARIABLEHEIGHT;pdbi.dwMask = pdbi.dwMask | DESKBANDINFO.DBIM.DBIM_BKCOLOR | DESKBANDINFO.DBIM.DBIM_TITLE; // Testenreturn S_OK;}public int GetWindow(out IntPtr phwnd){phwnd = Handle;return S_OK;}public int ContextSensitiveHelp(bool fEnterMode){return S_OK;}public int ShowDW([In] bool fShow){if (fShow)Show();elseHide();return S_OK;}public virtual void ClearResources(){}public int CloseDW([In] uint dwReserved){ClearResources();Dispose(true);return S_OK;}public int ResizeBorderDW(RECT prcBorder, [In, MarshalAs(UnmanagedType.IUnknown)] IntPtr punkToolbarSite, bool fReserved){return E_NOTIMPL;}#endregion#region Register / Unregister[ComRegisterFunctionAttribute]public static void Register(Type t){string guid = t.GUID.ToString("B");DeskBandInfoAttribute[] deskBandInfo = (DeskBandInfoAttribute[])t.GetCustomAttributes(typeof(DeskBandInfoAttribute), false);// Register only the extension if the attribute DeskBandInfo is used.if (deskBandInfo.Length == 1){RegistryKey rkClass = Registry.ClassesRoot.CreateSubKey(@"CLSID\" + guid);RegistryKey rkCat = rkClass.CreateSubKey("Implemented Categories");string _displayName = t.Name;string _helpText = t.Name;if (deskBandInfo[0].DisplayName != null){_displayName = deskBandInfo[0].DisplayName;}if (deskBandInfo[0].HelpText != null){_helpText = deskBandInfo[0].HelpText;}rkClass.SetValue(null, _displayName);rkClass.SetValue("MenuText", _displayName);rkClass.SetValue("HelpText", _helpText);// TaskBarrkCat.CreateSubKey("{00021492-0000-0000-C000-000000000046}");Console.WriteLine(String.Format("{0} {1} {2}", guid, _displayName, "successfully registered."));}else{Console.WriteLine(guid + " has no attributes");}}[ComUnregisterFunctionAttribute]public static void Unregister(Type t){string guid = t.GUID.ToString("B");DeskBandInfoAttribute[] deskBandInfo = (DeskBandInfoAttribute[])t.GetCustomAttributes(typeof(DeskBandInfoAttribute), false);if (deskBandInfo.Length == 1){string _displayName = t.Name;if (deskBandInfo[0].DisplayName != null){_displayName = deskBandInfo[0].DisplayName;}Registry.ClassesRoot.CreateSubKey(@"CLSID").DeleteSubKeyTree(guid);Console.WriteLine(String.Format("{0} {1} {2}", guid, _displayName, "successfully removed."));}else{Console.WriteLine(guid + " has no attributes");}}#endregion}
}

View Code

DiskInfo,该类继承DeskBand,用于实现业务和界面,代码如下:

using DataStruct;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WCFServer;namespace MyDiskInfo
{/// <summary>/// 固态硬盘信息显示控件/// </summary>public partial class DiskInfoCtrl : UserControl{#region 字段private Thread _thread = null;private IClientServer _client = new ClientServer();private double _width = 140;private double _height = 30;private int _interval = 60 * 1000; //刷新间隔private DiskModel _diskInfo = null;private DiskInfoViewModel _model = new DiskInfoViewModel();#endregion#region 构造函数public DiskInfoCtrl(){InitializeComponent();//尺寸this.Width = _width;this.Height = _height;this.DataContext = _model;ShowDiskInfo();_thread = new Thread(new ThreadStart(() =>{while (true){Thread.Sleep(_interval);ShowDiskInfo();}}));_thread.Start();}#endregion#region 显示硬盘信息/// <summary>/// 显示硬盘信息/// </summary>private void ShowDiskInfo(){BackWork.Run(() =>{_diskInfo = _client.GetDiskInfo();}, () =>{_model.Info = string.Format("{0}G {1}G {2}PE", _diskInfo.LBA_TodayWrite, _diskInfo.LBA_Write, _diskInfo.PE);}, (ex) => { });}#endregion#region 释放资源public void ClearResources(){if (_thread != null){_thread.Abort();_thread = null;}}#endregion}#region DiskInfoViewModelpublic class DiskInfoViewModel : INotifyPropertyChanged{public event PropertyChangedEventHandler PropertyChanged;private string _Info;public string Info{get { return _Info; }set{_Info = value;OnPropertyChanged("Info");}}public void OnPropertyChanged(string name){if (PropertyChanged != null){PropertyChanged(this, new PropertyChangedEventArgs(name));}}}#endregion}

View Code

实现业务界面的WPF用户控件:

XAML:

<UserControl x:Class="MyDiskInfo.DiskInfoCtrl"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="120" ><Grid><TextBlock Text="{Binding Info}" FontFamily="微软雅黑" FontSize="12" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock></Grid>
</UserControl>

View Code

后台代码:

using DataStruct;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WCFServer;namespace MyDiskInfo
{/// <summary>/// 固态硬盘信息显示控件/// </summary>public partial class DiskInfoCtrl : UserControl{#region 字段private Thread _thread = null;private IClientServer _client = new ClientServer();private double _width = 140;private double _height = 30;private int _interval = 60 * 1000; //刷新间隔private DiskModel _diskInfo = null;private DiskInfoViewModel _model = new DiskInfoViewModel();#endregion#region 构造函数public DiskInfoCtrl(){InitializeComponent();//尺寸this.Width = _width;this.Height = _height;_diskInfo = _client.GetDiskInfo();_model.Info = string.Format("{0}G {1}G {2}PE", _diskInfo.LBA_TodayWrite, _diskInfo.LBA_Write, _diskInfo.PE);this.DataContext = _model;_thread = new Thread(new ThreadStart(() =>{while (true){Thread.Sleep(_interval);BackWork.Run(() =>{_diskInfo = _client.GetDiskInfo();}, () =>{_model.Info = string.Format("{0}G {1}G {2}PE", _diskInfo.LBA_TodayWrite, _diskInfo.LBA_Write, _diskInfo.PE);}, (ex) => { });}}));_thread.Start();}#endregion#region 释放资源public void ClearResources(){if (_thread != null){_thread.Abort();_thread = null;}}#endregion}#region DiskInfoViewModelpublic class DiskInfoViewModel : INotifyPropertyChanged{public event PropertyChangedEventHandler PropertyChanged;private string _Info;public string Info{get { return _Info; }set{_Info = value;OnPropertyChanged("Info");}}public void OnPropertyChanged(string name){if (PropertyChanged != null){PropertyChanged(this, new PropertyChangedEventArgs(name));}}}#endregion}

View Code

类库是需要签名的:

其它代码就不粘了,上面粘的代码,去掉业务代码,写个测试的界面,也可以跑起来,程序写好后,怎么安装呢,我写了个Install.bat代码如下:

@echo off"%~dp0gacutil.exe" /if "%~dp0MyDiskInfo.dll"
"%~dp0RegAsm.exe" "%~dp0MyDiskInfo.dll"
reg import "%~dp0register.reg""%~dp0ServiceInstallUtil\InstallUtil.exe" "%~dp0MyDiskInfoService.exe"
sc config MyDiskInfoService start= auto
sc config MyDiskInfoService type= interact type= own
net start MyDiskInfoServicetaskkill /f /im explorer.exe
start explorer.exe Pause

View Code

我是Win10系统,由于GitHub上的,安装之后DeskBand并没有显示在Windows工具栏菜单中,可能是注册表写的位置不对,我写了个register.reg,代码如下:

Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\CLSID\{C7B92F87-7E59-467F-A6FF-9518DADA1C2C}]
@="DiskInfo"
"MenuText"="DiskInfo"
"HelpText"="Show DiskInfo"[HKEY_CLASSES_ROOT\CLSID\{C7B92F87-7E59-467F-A6FF-9518DADA1C2C}\Implemented Categories][HKEY_CLASSES_ROOT\CLSID\{C7B92F87-7E59-467F-A6FF-9518DADA1C2C}\Implemented Categories\{00021492-0000-0000-C000-000000000046}][HKEY_CLASSES_ROOT\CLSID\{C7B92F87-7E59-467F-A6FF-9518DADA1C2C}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}][HKEY_CLASSES_ROOT\CLSID\{C7B92F87-7E59-467F-A6FF-9518DADA1C2C}\InprocServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="MyDiskInfo.DiskInfo"
"Assembly"="MyDiskInfo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bec8b29cd4c20aff"
"RuntimeVersion"="v4.0.30319"[HKEY_CLASSES_ROOT\CLSID\{C7B92F87-7E59-467F-A6FF-9518DADA1C2C}\InprocServer32\1.0.0.0]
"Class"="MyDiskInfo.DiskInfo"
"Assembly"="MyDiskInfo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bec8b29cd4c20aff"
"RuntimeVersion"="v4.0.30319"[HKEY_CLASSES_ROOT\CLSID\{C7B92F87-7E59-467F-A6FF-9518DADA1C2C}\ProgId]
@="MyDiskInfo.DiskInfo"

View Code

最终效果图:

存在的问题:Win10系统下正常,Win7操作系统下,背景无法透明,如果DeskBand修改为继承Form并且设置TransparenceKey属性为BackColor,依然无法实现透明,最后放弃了。

由于DeskBand没有权限读取固态硬盘信息,我写了个Windows服务来读取信息,Windows服务的安全性设置为“这是完全可信的应用程序”,使用WCF实现进程间管道通信来把数据传给DeskBand显示。

Windows服务注册为开机启动,但是DeskBand不是开机启动,需要自己勾选能才显示出来,DeskBand的自动启动我没有实现,网上资料多是C++的,用勾子实现。

完整代码如下:

MyDiskInfo_WPF版_固态硬盘写入量信息嵌入任务栏工具栏

posted on 2019-04-02 11:46 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/10641706.html

C# Winform WPF DeskBand 窗体嵌入任务栏,在任务栏显示文字相关推荐

  1. 如何将Win7任务栏缩略图改为显示文字提示

    在Win7的优越性中, Win7任务栏缩略图 是一个很大的特点,但在系统运行方面 Win7任务栏缩略图 又是比较占内存大的功能,很多时候为了提高系统的运行速度,不得不把此功能关闭,下面我们就来学习如何 ...

  2. 在WinForm应用程序中嵌入WPF控件(转)

      我们知道,在WPF界面上添加WinForm的控件需要使用WindowsFormHost类.而在WinForm界面上添加WPF控件该如何做呢?有没有类似的类呢?明显是有的,ElementHost就是 ...

  3. 【转】C#自定义控件:WinForm将其它应用程序窗体嵌入自己内部

    PS:文末的附件已更新,这次我放到博客园里面了,不会弹出广告,放心下载,O(∩_∩)O谢谢! 这是最近在做的一个项目中提到的需求,把一个现有的窗体应用程序界面嵌入到自己开发的窗体中来,看起来就像自己开 ...

  4. C#自定义控件:WinForm将其它应用程序窗体嵌入自己内部

    这是最近在做的一个项目中提到的需求,把一个现有的窗体应用程序界面嵌入到自己开发的窗体中来,看起来就像自己开发的一样(实际上--跟自己开发的还是有一点点区别的,就是内嵌程序和宿主程序的窗口激活状态问题) ...

  5. winform窗体嵌入窗体

    有些时候我们需要将子窗体嵌入父窗体来实现一些效果这时该怎么做呢. //通过给panel加载子元素实现Form1 form =new Form1();form.FormBorderStyle = For ...

  6. [WPF疑难]避免窗口最大化时遮盖任务栏

    [WPF疑难]避免窗口最大化时遮盖任务栏 周银辉 WPF窗口最大化时有个很不好的现象是:如果窗口的WindowStyle被直接或间接地设置为None后(比如很多情况下你会覆盖默认的窗体样式,即不采用W ...

  7. WPF中用于嵌入其他进程窗口的自定义控件(AppContainer)

    原文:WPF中用于嵌入其他进程窗口的自定义控件(AppContainer) 版权声明:本文为博主原创文章,转载请注明作者和出处 https://blog.csdn.net/ZZZWWWPPP11199 ...

  8. winform wpf 全屏最大化

    winform & wpf 全屏最大化 全屏最大化条件:(隐藏状态栏,) 需要设置windows窗口模式=None, 窗口状态最大化MAX 特殊需求:窗口状态切换(全屏–>普通大小+窗口 ...

  9. Winform SunnyUI主题窗体属性:图标,可变大小,标题栏扩展按钮

    Winform SunnyUI主题窗体属性:图标,可变大小,标题栏扩展按钮 把窗体的AutoScaleMode从Font设置为None,否则可能出现因为屏幕分辨率而导致的窗体变形. 拖拽调整窗体大小 ...

最新文章

  1. VBS字符编码的说明
  2. VC++2005 CString和char*的相互转换
  3. 【转】Spring事务超时时间可能存在的错误认识
  4. [一维粒子模拟 version3.6]实现initial.m函数
  5. 数据结构与算法:排序算法的稳定性以及各性能比较python实现
  6. 通过Roslyn构建自己的C#脚本(更新版)
  7. Java之String,StringBuffer,StringBuilder比较
  8. 6-Hadoop之旅-Hive(二)
  9. 对FT证券系统故障的分析与思考
  10. JavaEE初阶-计算机是如何工作的
  11. 固态硬盘计算机怎么自定义分区,固态硬盘分区,详细教您固态硬盘怎么分区
  12. 【整理】【原创】 什么是一维表,什么是二维表?----不同于 1维数组,2维数组
  13. 【HNOI 2018】寻宝游戏
  14. redis集群拓扑_Redis拓扑
  15. Codeforces 869 C. The Intriguing Obsession (组合数学)
  16. C语言报名里面培训怎么填,庄河c语言编程学习,庄河学c语言编程培训,庄河学c语言编程报个培训班怎么样...
  17. AcWing春季每日一题 Week1
  18. 查找-查找的基本概念
  19. python图像rgb转灰度
  20. 工程伦理--10.3 工程师的职业美德内涵

热门文章

  1. Netflix(奈飞)--SpringCloud
  2. Mary_Morton
  3. 如何高效管理 React Native 项目中的图片资源
  4. 【极客大挑战 2019】Havefun
  5. KVO和KVC的区别
  6. 信邦智能通过深交所注册:拟募资近7亿 李罡家族为实控人
  7. 反汇编工具capstone的使用
  8. ACM-奋斗的小蜗牛
  9. 银行卡大小的充电宝,你有吗?
  10. 数商云•瓴犀产品3.0战略发布会完美告捷,引领企业全链业务协同数字化发展