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}"
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).