IDeskBand2 implementation crashes

463 views Asked by At

I have created a sample template for a future project that implements IDeskBand2.

The registration with gacuti and regasm works, it is also displayed in the toolbar. If I want to display / execute it, the explorer crashes.

For the creation I used the documentation of Mircosoft and pinvoke.

I compared my project with media-control-deskband and tried some things (COMInterop file in my project, compare code etc.) But can't find the cause, guess it's because of a faulty implementation.

Here's my implementation.

IDeskBand2 Interface:

/// <summary>
/// Gets information about a band object.
/// </summary>
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("EB0FE172-1A3A-11D0-89B3-00A0C90A90AC")]
public interface IDeskBand : IDockingWindow
{
    /// <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></returns>
    [PreserveSig]
    int GetBandInfo(UInt32 dwBandID, DeskBandInfoViewMode 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
{
    /// <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>
    /// 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);

    /// <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);
}

IDeskBand2 in use: (GetBandInfo function is tested and works correctly.)

    /// <summary>
/// Basic class for a DeskBand object
/// </summary>
/// <example>
/// [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 : UserControl, IDeskBand2
{
    #region Constants

    private const int S_OK = 0;
    private const int E_NOTIMPL = unchecked((int)0x80004001);

    #endregion

    #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 horinzortal.)
    /// </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 IDeskBand2

    public virtual int CanRenderComposited(out bool pfCanRenderComposited)
    {
        pfCanRenderComposited = true;
        return S_OK;
    }

    public int GetCompositionState(out bool pfCompositionEnabled)
    {
        pfCompositionEnabled = false;
        return S_OK;
    }

    public int SetCompositionState(bool fCompositionEnabled)
    {
        fCompositionEnabled = true;
        return S_OK;
    }

    public int GetBandInfo(uint dwBandID, DeskBandInfoViewMode dwViewMode, ref DESKBANDINFO pdbi)
    {
        if (pdbi.dwMask.HasFlag(DeskBandInfoMasks.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(DeskBandInfoViewMode.DBIF_VIEWMODE_FLOATING) || dwViewMode.HasFlag(DeskBandInfoViewMode.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(DeskBandInfoMasks.DBIM_MAXSIZE))
        {
            if (dwViewMode.HasFlag(DeskBandInfoViewMode.DBIF_VIEWMODE_FLOATING) || dwViewMode.HasFlag(DeskBandInfoViewMode.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(DeskBandInfoMasks.DBIM_INTEGRAL))
        {
            if (dwViewMode.HasFlag(DeskBandInfoViewMode.DBIF_VIEWMODE_FLOATING) || dwViewMode.HasFlag(DeskBandInfoViewMode.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(DeskBandInfoMasks.DBIM_ACTUAL))
        {
            if (dwViewMode.HasFlag(DeskBandInfoViewMode.DBIF_VIEWMODE_FLOATING) || dwViewMode.HasFlag(DeskBandInfoViewMode.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(DeskBandInfoMasks.DBIM_TITLE))
        {
            pdbi.wszTitle = this.Title;
        }

        pdbi.dwModeFlags = DeskBandInfoModeFlag.DBIMF_ALWAYSGRIPPER | DeskBandInfoModeFlag.DBIMF_NORMAL | DeskBandInfoModeFlag.DBIMF_VARIABLEHEIGHT;
        pdbi.dwMask = pdbi.dwMask | DeskBandInfoMasks.DBIM_BKCOLOR | DeskBandInfoMasks.DBIM_TITLE; // Testen

        return S_OK;
    }

    public int CloseDW([In] uint dwReserved)
    {
        Dispose(true);
        return S_OK;
    }

    public int ResizeBorderDW(IntPtr prcBorder, [In, MarshalAs(UnmanagedType.IUnknown)] object punkToolbarSite, bool fReserved)
    {
        return E_NOTIMPL;
    }

    public int ShowDW([In] bool fShow)
    {
        if (fShow)
            Show();
        else
            Hide();

        return S_OK;
    }

    public int GetWindow(out IntPtr phwnd)
    {
        phwnd = Handle;
        return S_OK;
    }

    public int ContextSensitiveHelp(bool fEnterMode)
    {
        return S_OK;
    }

    #endregion

    #region COM

    [ComRegisterFunctionAttribute]
    public static void Register(Type t)
    {
        string guid = t.GUID.ToString("B");

        RegistryKey rkClass = Registry.ClassesRoot.CreateSubKey(@"CLSID\" + guid);
        RegistryKey rkCat = rkClass.CreateSubKey("Implemented Categories");

        DeskBandInfoAttribute[] deskBandInfo = (DeskBandInfoAttribute[])
            t.GetCustomAttributes(typeof(DeskBandInfoAttribute), false);

        string _displayName = t.Name;
        string _helpText = t.Name;

        if (deskBandInfo.Length == 1)
        {
            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);

        // TaskBar
        rkCat.CreateSubKey("{00021492-0000-0000-C000-000000000046}");
    }

    [ComUnregisterFunctionAttribute]
    public static void Unregister(Type t)
    {
        string guid = t.GUID.ToString("B");

        DeskBandInfoAttribute[] deskBandInfo = (DeskBandInfoAttribute[])
            t.GetCustomAttributes(typeof(DeskBandInfoAttribute), false);

        Registry.ClassesRoot.CreateSubKey(@"CLSID").DeleteSubKeyTree(guid);
    }

    #endregion

    public DeskBand()
    {
        InitializeComponent();
    }

    private void InitializeComponent()
    {
        this.Name = "DeskBand";
    }
}
}

The actual extension without Designer Code:

namespace TaskbarSampleExt
{
    [Guid("2D53D9CC-0288-4511-A387-B330044C63EA")]
    [DeskBandInfo("Beispiel Erweiterung", "Diese ist eine Beispiel Erweiterung für die Taskleiste.")]
    public partial class SampleExtension : DeskBand
    {

        public SampleExtension()
        {
            this.MinSize = new Size(90, 40);
            this.MinSizeVertical = new Size(90, 40);
            this.Title = "Beispiel Erweiterung";

            InitializeComponent();
        }

    }
}

Thank you for your time

Brocken files

1

There are 1 answers

4
Simon Mourier On BEST ANSWER

You didn't copy/paste the original code properly.

In .NET when you declare a derived interface say IDeskBand2 from IDeskBand, you must redeclare all the methods of the base interface (and recursively, you can just omit IUnknown of course).

Like this (if you want the derivation appear in .NET):

public interface IDeskBand2 : IDeskBand
{
    // IOleWindow
    new int GetWindow(out IntPtr phwnd);
    new int ContextSensitiveHelp(bool fEnterMode);

    // IDockingWindow
    new int ShowDW(bool bShow);
    new int CloseDW(UInt32 dwReserved);
    new int ResizeBorderDW(RECT rcBorder, IntPtr punkToolbarSite, bool fReserved);

    // IDeskBand
    new int GetBandInfo(UInt32 dwBandID, DESKBANDINFO.DBIF dwViewMode, ref DESKBANDINFO pdbi);

    // IDeskBand2
    int CanRenderComposited(out bool pfCanRenderComposited);
    ....
}

or simply like this:

public interface IDeskBand2
{
    // IOleWindow
    int GetWindow(out IntPtr phwnd);
    int ContextSensitiveHelp(bool fEnterMode);

    // IDockingWindow
    int ShowDW(bool bShow);
    int CloseDW(UInt32 dwReserved);
    int ResizeBorderDW(RECT rcBorder, IntPtr punkToolbarSite, bool fReserved);

    // IDeskBand
    int GetBandInfo(UInt32 dwBandID, DESKBANDINFO.DBIF dwViewMode, ref DESKBANDINFO pdbi);

    // IDeskBand2
    int CanRenderComposited(out bool pfCanRenderComposited);
    ....
}