I have a COM add-in written in C#, that works perfectly fine with Microsoft Office.
There was a GitHub issue asking if the add-in supported the VB6 IDE; is there anything different I need to do, to make it work with Visual Studio 6.0?
Here's the relevant class listing:
using System;
using Extensibility;
using Microsoft.Vbe.Interop;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows.Forms;
namespace Rubberduck
{
[ComVisible(true)]
[Guid(ClassId)]
[ProgId(ProgId)]
[EditorBrowsable(EditorBrowsableState.Never)]
//underscores make classes invisible to VB6 object explorer
//Nothing breaks because we declare a ProgId
public class _Extension : IDTExtensibility2, IDisposable
{
public const string ClassId = "8D052AD8-BBD2-4C59-8DEC-F697CA1F8A66";
public const string ProgId = "Rubberduck.Extension";
private App _app;
public void OnAddInsUpdate(ref Array custom)
{
}
public void OnBeginShutdown(ref Array custom)
{
}
public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
{
try
{
// these casts fail when host is VB6 environment
_app = new App((VBE)Application, (AddIn)AddInInst);
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Rubberduck Add-In could not be loaded", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public void OnStartupComplete(ref Array custom)
{
if (_app != null)
{
_app.CreateExtUi();
}
}
public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom)
{
Dispose();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing & _app != null)
{
_app.Dispose();
}
}
}
}
The casts to VBE
and AddIn
types simply blow up. The assembly is registered and works exactly as intended in Office.
I'm having a bit of a hard time finding documentation about extending VB6, but my understanding is that the interfaces involved are the same - and by attaching to the VB6 process, breaking just before the casts, and inspecting the Application
object, I can see all the members I'm expecting to see there.
Why is it not working then? Here are the relevant references from the project file:
<Reference Include="extensibility, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
...
<COMReference Include="VBIDE">
<Guid>{0002E157-0000-0000-C000-000000000046}</Guid>
<VersionMajor>5</VersionMajor>
<VersionMinor>3</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
The problem is that VBA has it's own VBIDE Type Library, and VB6 also has it's own VBIDE Type Library. Both Type Libraries are very similar (although the VB6 version is much richer), and both expose the IDTExtensibility2
interface. Furthermore, as IDTExtensibility2
was introduced with VB6 and Office 2000's VBA 6.x, there are also versions of VBIDE for VB5 and, I assume, for Office 97's VBA 5.x, that expose the original IDTExtensibility
.
Contrary to Hans Passant's answer, the add-in is NOT an Office add-in, but is in fact a VBE add-in, so it works in any host that supports VBA 6/7 (Office, AutoCAD, CorelDraw, SolidWorks, etc.) and it can absolutely work in VB6 too... It just takes a little more work.
If you want to support VB6 (or VB5, or VBA 5.x) then you'll need to add a reference to the relevant Interop assemblies, and you'll need to cast to the appropriate types on connecting.
I posted a proof of concept on CodeReview that supports VB6 and VBA 6.x\7.x. It's far from a complete implementation, but you'll see that I created an IVBE interface to abstract the different VBIDE implementations.