VBA运行时错误:'459'使用自定义ActiveX控件运行userform时发生外部exception

我通过创build一个简单的COM-Visible类在C#中创build了一个自定义的ActiveX控件。 我能够构build我的C#解决scheme,并且可以在Excel 2010(32位)中看到该控件,并且可以将我的自定义控件添加到VBA用户窗体并正确查看。 我正在运行Windows 7 64位企业版。 但是,当我尝试运行UserForm时,VBA引发Run-time error '459': External exception

您可以从下面的图片中看到,我已经成功地将自定义控件添加到UserForm(只是一个简单的button):

在这里输入图像说明

我实际上可以点击我的ActiveX控件中的button,它会触发一个显示消息框的OnButtonClick事件:

在这里输入图像说明

该控件也可在其他控件下使用,这使我可以在VBA工具箱中看到它:

在这里输入图像说明

我已经尝试了很多解决scheme,但目前为止没有任何工作,我简直无法在VBA UserForm中使用我的自定义控件。 这是我迄今为止所尝试的:

  • 使用RegAsm.exe“控制DLLpath”/ codebase为64和32位
  • 尝试RegAsm.exe没有/ codebase
  • 首先使用RegAsm.exe进行32位,然后使用64位,只使用32位,只使用64位
  • 在VBA编辑器中的Tools / References下添加了引用到我的自定义用户控件类,这现在允许我看到暴露的COM接口与方法等,这现在抛出'459' Object or class does not support the set of events
  • 我的项目有属性/构build下的COM-Visible勾选,也在汇编信息/使程序集COM可见

我也尝试在Excel 2016 64位Windows 10 64位计算机上使用我的代码。 我可以构build解决scheme,但是在VBA的其他控件下不可见控件。 我已经执行了注册DLL文件的所有RegAsm命令,但它不会显示在那里。 这是超级奇怪的行为。 我试图创build一个ActiveX控件可以在32位和64位Excel上工作,因为64位版本的Office不支持32位现有的VBA控件(我们需要ListView,DateTimePicker)。 我们有一个庞大的代码库,我们无法从VBA切换到不同的平台,我们正在从32位系统迁移到64位系统。 我无法find比我现在更优雅的解决scheme,这将是理想的,但它的行为如此怪异,拒绝工作。

这里是我的C#代码(这是垃圾,只是做了一个快速的testing解决scheme),接着我find了一个示例,这是唯一的解决scheme,实际上允许我将控件添加到用户窗体:

 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using Microsoft.Win32; namespace ActiveXTest2 { [ProgId("ActiveXTest2.CustomUserControl")] [ClassInterface(ClassInterfaceType.AutoDual), ComSourceInterfaces(typeof(IUserControlEvents))] public partial class CustomUserControl : UserControl { private ListView listView1; public CustomUserControl() { InitializeComponent(); } // register COM ActiveX object [ComRegisterFunction] public static void RegisterClass(string key) { StringBuilder skey = new StringBuilder(key); skey.Replace(@"HKEY_CLASSES_ROOT\", ""); Type myType1 = Type.GetTypeFromProgID("ActiveXTest2.CustomUserControl"); Console.WriteLine("ProgID=ActiveXTest2.CustomUserControl GUID={0}.", myType1.GUID); TextWriter tw = File.CreateText("guid.txt"); tw.WriteLine(skey.ToString()); tw.WriteLine(myType1.GUID.ToString()); tw.Close(); RegistryKey regKey = Registry.ClassesRoot.OpenSubKey(skey.ToString(), true); RegistryKey ctrl = regKey.CreateSubKey("Control"); ctrl.Close(); RegistryKey inprocServer32 = regKey.OpenSubKey("InprocServer32", true); inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase); inprocServer32.Close(); regKey.Close(); } // Unregister COM ActiveX object [ComUnregisterFunction] public static void UnregisterClass(string key) { StringBuilder skey = new StringBuilder(key); skey.Replace(@"HKEY_CLASSES_ROOT\", ""); RegistryKey regKey = Registry.ClassesRoot.OpenSubKey(skey.ToString(), true); regKey.DeleteSubKey("Control", false); RegistryKey inprocServer32 = regKey.OpenSubKey("InprocServer32", true); regKey.DeleteSubKey("CodeBase", false); regKey.Close(); } public delegate void ControlEventHandler(); [Guid("0A415E38-372F-45fb-813B-D9558C787EB0")] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IUserControlEvents { [DispId(0x60020001)] void OnButtonClick(); } public interface ICOMCallable { int TestValue(); } public int TestValue() { return 0; } public event ControlEventHandler OnButtonClick; protected virtual void OnOnButtonClick() { MessageBox.Show("TEST", "", MessageBoxButtons.OK, MessageBoxIcon.Error); } private void InitializeComponent() { this.listView1 = new System.Windows.Forms.ListView(); this.SuspendLayout(); // // listView1 // this.listView1.Location = new System.Drawing.Point(4, 4); this.listView1.Name = "listView1"; this.listView1.Size = new System.Drawing.Size(228, 210); this.listView1.TabIndex = 0; this.listView1.UseCompatibleStateImageBehavior = false; // // CustomUserControl // this.Controls.Add(this.listView1); this.Name = "CustomUserControl"; this.Size = new System.Drawing.Size(235, 217); this.ResumeLayout(false); } private void button1_Click(object sender, EventArgs e) { OnOnButtonClick(); } } }