Cant create tool window (com add-in extension for vbide, vba)

121 views Asked by At

I am trying to write a simple extension for VBIDE and am stuck on creating a dockable window. The error I am getting is HRESULT 0x800401F3 on line:

_window = windows.CreateToolWindow(
                        _addin,
                        "VBAaddin.TestComponent",
                        "My CoolDoc", 
                        guid, 
                        ref control
                    );

Extension code:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Extensibility;
using Microsoft.Vbe.Interop;
using VB = Microsoft.Vbe.Interop;

namespace VBAaddin
{
    [
        ComVisible(true),
        ProgId("VBAaddin.Extension"),
        Guid("60A72993-8B93-4C71-81E8-87BC6DD85F5D"),
        ClassInterface(ClassInterfaceType.None),
        ComDefaultInterface(typeof(IDTExtensibility2)),
        EditorBrowsable(EditorBrowsableState.Never)
    ]
public class Extension : IDTExtensibility2
    {
        private VB.VBE _vbe;
        private VB.AddIn _addin;
        private VB.Window _window;
        public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
        {
            _vbe = (VB.VBE)Application;
            _addin = (VB.AddIn)AddInInst;

            switch (ConnectMode)
            {
                case ext_ConnectMode.ext_cm_Startup:
                    break;
                case ext_ConnectMode.ext_cm_AfterStartup:
                    InitializeExtension();
                    break;
            }
        }

        private void InitializeExtension()
        {
            MessageBox.Show("Initializing");
            try
            {
                try
                {
                    object control = null;
                    const string guid = "9A195073-D54B-4FFD-883C-EBBBEFD860F5";
                    Windows windows = _vbe.Windows;
                    _window = windows.CreateToolWindow(
                        _addin,
                        "VBAaddin.TestComponent",
                        "My CoolDoc", 
                        guid, 
                        ref control
                    );
                    _window.Visible = true;
                }
                catch (COMException exception)
                {
                    MessageBox.Show(exception.ToString());
                }
            }
            catch (Exception e)
            {
                MessageBox.Show($"{e.Message} {e.Source}");
            }

        }

        public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom)
        {
        }

        public void OnAddInsUpdate(ref Array custom)
        {
        }

        public void OnStartupComplete(ref Array custom)
        {
               InitializeExtension();
        }

        public void OnBeginShutdown(ref Array custom)
        {
        }
    }
}

TestComponent:

using System.Runtime.InteropServices;
using System.Windows.Controls;

namespace VBAaddin
{
    [
        ComVisible(true),
        ProgId("VBAaddin.TestComponent"),
        Guid("9A195073-D54B-4FFD-883C-EBBBEFD860F5")
    ]
    public partial class TestComponent : UserControl
    {
        public TestComponent()
        {
            InitializeComponent();
        }
    }
}

TestComponent.xaml:

<UserControl x:Class="VBAaddin.TestComponent"
             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" 
             xmlns:local="clr-namespace:VBAaddin"
             mc:Ignorable="d" 
             d:DesignHeight="200" d:DesignWidth="300">
    <Grid>
        <TextBox HorizontalAlignment="Center" Margin="0,82,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>

    </Grid>
</UserControl>

reg:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\VBA\VBE\6.0\Addins\VBAaddin.Extension]
"Description"="VBAaddin"
"FriendlyName"="VBAaddin"
"LoadBehavior"=dword:00000003

[HKEY_CURRENT_USER\Software\Microsoft\VBA\VBE\6.0\Addins64\VBAaddin.Extension]
"Description"="VBAaddin"
"FriendlyName"="VBAaddin"
"LoadBehavior"=dword:00000003

[HKEY_CLASSES_ROOT\CLSID\{60A72993-8B93-4C71-81E8-87BC6DD85F5D}]
@="VBAaddin.Extension"

[HKEY_CLASSES_ROOT\CLSID\{60A72993-8B93-4C71-81E8-87BC6DD85F5D}\ProgId]
@="VBAaddin.Extension"

[HKEY_CLASSES_ROOT\VBAaddin.Extension]
@="VBAaddin.Extension"

[HKEY_CLASSES_ROOT\VBAaddin.Extension\CLSID]
@="{60A72993-8B93-4C71-81E8-87BC6DD85F5D}"

[HKEY_CLASSES_ROOT\VBAaddin.TestComponent]
@="VBAaddin.TestComponent"

[HKEY_CLASSES_ROOT\CLSID\{9A195073-D54B-4FFD-883C-EBBBEFD860F5}]
@="VBAaddin.TestComponent"

[HKEY_CLASSES_ROOT\VBAaddin.TestComponent\CLSID]
@="{9A195073-D54B-4FFD-883C-EBBBEFD860F5}"
1

There are 1 answers

0
Mathieu Guindon On BEST ANSWER

You need TestComponent to be a WinForms user control; for a WPF UI you'll then need that user control to house a WPF interop host (dock/fill in the containing user control) that can load the XAML user control.

That's how Rubberduck 2.x did it ☺️

Note that there are a number of quirks with the COM interop between the native windows and the WinForms user control that can make it difficult to correctly tear down for a clean shutdown of your addin (part of why Rubberduck 3.x is moving away from them).