无法将 COM 对象转换为 Microsoft.Vbe.Interop.VBE
Unable to cast COM object to Microsoft.Vbe.Interop.VBE
我有一个 COM add-in written in C#,可以与 Microsoft Office 完美配合。
有一个GitHub issue asking if the add-in supported the VB6 IDE;我需要做些什么才能使其与 Visual Studio 6.0 一起使用?
这是相关的 class 清单:
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();
}
}
}
}
对 VBE
和 AddIn
类型的强制转换完全失败了。该程序集已注册 ,并且在 Office.
中完全按照预期工作
我很难找到有关扩展 VB6 的文档,但我的理解是所涉及的接口是相同的 - 并且通过附加到 VB6 进程,在强制转换之前中断,并检查Application
对象,我可以在那里看到我希望看到的所有成员。
为什么它不工作呢?以下是项目文件中的相关参考资料:
<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>
问题是 VBA 有它自己的 VBIDE 类型库,VB6 也有它自己的 VBIDE 类型库。这两个类型库非常相似(尽管 VB6 版本更丰富),并且都公开了 IDTExtensibility2
接口。此外,由于 IDTExtensibility2
是与 VB6 和 Office 2000 的 VBA 6.x 一起引入的,所以还有用于 VB5 的 VBIDE 版本,我认为,用于 Office 97 的 VBA [=26] =],即暴露原IDTExtensibility
.
与 Hans Passant 的回答相反,该加载项不是 Office 加载项,实际上是 VBE 加载项,因此它可以在任何支持 VBA 6/7 ( Office, AutoCAD, CorelDraw, SolidWorks, 等等)而且它也绝对可以在 VB6 中工作...只是需要多做一些工作。
如果您想支持 VB6(或 VB5,或 VBA 5.x),则需要添加对相关 Interop 程序集的引用,和 您需要在连接时转换为适当的类型。
我发布了一个支持 VB6 和 VBA 6.x.x 的 proof of concept on CodeReview。它远非完整的实现,但您会看到我创建了一个 IVBE 接口来抽象不同的 VBIDE 实现。
我有一个 COM add-in written in C#,可以与 Microsoft Office 完美配合。
有一个GitHub issue asking if the add-in supported the VB6 IDE;我需要做些什么才能使其与 Visual Studio 6.0 一起使用?
这是相关的 class 清单:
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();
}
}
}
}
对 VBE
和 AddIn
类型的强制转换完全失败了。该程序集已注册 ,并且在 Office.
我很难找到有关扩展 VB6 的文档,但我的理解是所涉及的接口是相同的 - 并且通过附加到 VB6 进程,在强制转换之前中断,并检查Application
对象,我可以在那里看到我希望看到的所有成员。
为什么它不工作呢?以下是项目文件中的相关参考资料:
<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>
问题是 VBA 有它自己的 VBIDE 类型库,VB6 也有它自己的 VBIDE 类型库。这两个类型库非常相似(尽管 VB6 版本更丰富),并且都公开了 IDTExtensibility2
接口。此外,由于 IDTExtensibility2
是与 VB6 和 Office 2000 的 VBA 6.x 一起引入的,所以还有用于 VB5 的 VBIDE 版本,我认为,用于 Office 97 的 VBA [=26] =],即暴露原IDTExtensibility
.
与 Hans Passant 的回答相反,该加载项不是 Office 加载项,实际上是 VBE 加载项,因此它可以在任何支持 VBA 6/7 ( Office, AutoCAD, CorelDraw, SolidWorks, 等等)而且它也绝对可以在 VB6 中工作...只是需要多做一些工作。
如果您想支持 VB6(或 VB5,或 VBA 5.x),则需要添加对相关 Interop 程序集的引用,和 您需要在连接时转换为适当的类型。
我发布了一个支持 VB6 和 VBA 6.x.x 的 proof of concept on CodeReview。它远非完整的实现,但您会看到我创建了一个 IVBE 接口来抽象不同的 VBIDE 实现。