Search code examples
c#.netwinformsinteropwinforms-interop

Host IDeskBand in a Windows Form


I'm trying to display the Address toolbar from the Windows Taskbar in my own WinForm. I can get the CLSID of the Address toobar ({01E04581-4EEE-11d0-BFE9-00AA005B4383}), and I can get an IDeskBand reference to it. But... then what?

Guid bandCLSID = new Guid("{01E04581-4EEE-11d0-BFE9-00AA005B4383}");
Type bandType = Type.GetTypeFromCLSID(bandCLSID);
IDeskBand deskband = (IDeskBand)Activator.CreateInstance(bandType);

I've tried hosting it in an AxHost, but the Address toolbar is not an ActiveX control. I've tried calling

(deskband as IOleObjectWithSite).SetSite(various interfaces);

or

(deskband as IDockingWindow).ShowDW(true);

as well as various other interfaces and their methods, but nothing I do seems to get me anywhere. I'd be overjoyed if I could actually see that toolbar appear anywhere. But I can't seem to bridge the gap between having the IDeskBand reference and plugging it into my Windows Form.

Has anybody attempted this before, and gotten further than I have?


Solution

  • I don't think this is supported, as a DeskBand is supposed to be hosted by Explorer, but here is a sample Form code that demonstrates how to do it and should help to get you started.

    The idea is you need to be the "Site", instead of Explorer. If you look at the documentation here Creating Custom Explorer Bars, Tool Bands, and Desk Bands, you need to ensure your code behave like Explorer behaves. So, the fist thing to do is to give a "Site" implementation to the desk band object, and the first interface this implementation needs to provide is IOleWindow. The desk band object will ask your "Site" what is the parent windows handle. Just give the form's handle (for example) and the desk band will display itself as a Form's child:

    enter image description here

    NOTE: You can't use any Form or Control class as the IOleWindow implementer because it's already implementing it behind the scene (Winforms implementation), and this implementation is very specific, so you'll need a custom site as demonstrated here.

    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            private IObjectWithSite _band = (IObjectWithSite)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("{01E04581-4EEE-11d0-BFE9-00AA005B4383}")));
            private BandSite _site;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            protected override void CreateHandle()
            {
                base.CreateHandle();
                if (_site == null)
                {
                    _site = new BandSite(Handle);
                    _band.SetSite(_site);
                }
            }
    
            private class BandSite : IOleWindow
            {
                private IntPtr _hwnd;
    
                public BandSite(IntPtr hwnd)
                {
                    _hwnd = hwnd;
                }
    
                void IOleWindow.GetWindow(out IntPtr hwnd)
                {
                    hwnd = _hwnd;
                }
    
                void IOleWindow.ContextSensitiveHelp(int fEnterMode)
                {
                    throw new NotImplementedException();
                }
            }
        }
    
        [ComImport, Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IObjectWithSite
        {
            void SetSite([MarshalAs(UnmanagedType.IUnknown)] object pUnkSite);
    
            [return: MarshalAs(UnmanagedType.IUnknown)]
            object GetSite(ref Guid riid);
        }
    
        [ComImport, Guid("00000114-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IOleWindow
        {
            void GetWindow(out IntPtr hwnd);
            void ContextSensitiveHelp(int fEnterMode);
        }
    }