无法从VBA实例化使用C#编写的COM对象(VB6可以)

12

我使用VS 2008,这是我的COM对象

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace TestCom
{    
    [Guid("9E5E5FB2-219D-4ee7-AB27-E4DBED8E123E")]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ProgId("Test9.COMINT")]
    public class TestComClass  
    { 
        public void Init(string userid, string password)
        {
            MessageBox.Show(string.Format("{0}/{1}", userid, password));
        }       
    }
}
如果我按照以下步骤在生产机器上构建并注册它
REGASM /CODEBASE TESTCOM.DLL

从一个简单的VB6应用程序中,这个可以正常工作。

Private Sub Form_Load()
  Dim o As Object
  Set o = CreateObject("Test9.COMINT")
  o.Init "A", "B" 
End Sub

在Excel的VBA中调用完全相同的代码会导致

"automation error" (0x80131700)

在开发机器上一切正常,但是在仅安装.NET和MS Office的生产机器上却无法正常工作。

更新

我认为这与.NET框架在Excel下未能正确初始化有关。如果我使用Filemon,我可以看到它在寻找MSCORWKS.DLL时跳过了。当我从VBScript调用相同的对象时,它可以很好地找到MSCorwks.dll。

当我从VBA调用CorBindToCurrentRunTime来强制加载CLR时,有趣的是我得到了完全相同的HRESULT (0x80131700),就像在VBA中使用CreateObject()一样。

因此,我认为这是一个框架初始化问题。


我刚刚尝试了一下重现这个问题,它在我的机器上也正常工作。但愿我能提供更多帮助。 - JoshBerke
因为你的机器上有Visual Studio等工具,我敢打赌。当我有解决方案时,我一定会在这里发布。感谢大家的时间。 - rc1
@rc1: 太棒了... Sysinternals 再次拯救了一天! :) - Vyas Bharghava
5个回答

13

我将回答自己的问题,希望能够避免其他人经历我刚刚经历的数小时的乏味苦差。

如果你看到这个信息,那是因为基于.NET的COM程序集找不到.NET框架。

解决方案很简单。创建一个包含以下内容的文件:

<?xml version="1.0"?>
<configuration>
  <startup>
   <supportedRuntime version="v2.0.50727"/>
  </startup>
</configuration>

将其命名为“Excel.Exe.Config”,并将其放置在与“EXCEL.EXE”相同的目录中。
问题解决了!

很好,我从来没有想到过。 - JoshBerke
7
我不建议这样做,尤其是对于一个真正的部署应用程序(即,请不要在用户机器上部署Excel.exe.config文件!)。Excel是一个共享的应用程序宿主,您并不真正“拥有”它——这个配置文件改变了Excel中所有托管代码的工作方式。这将破坏任何未使用CLR 2.0的托管Excel插件。您应该能够通过正确的注册(检查对象的CLSID注册表项下的CLR版本)和/或一个CLR加载shim获得相同的效果。 - nitzmahone


1

RC1,我使用你的VBScript代码和Office 2007的Excel进行了测试,一切正常。

既然你能够在VB6表单中创建COM对象,我们应该假设你的.NET框架没有问题。你能否排除VBA的问题?你能否创建一个.vbs文件并将以下内容放入其中:

Dim o As Object  
Set o = CreateObject("Test9.COMINT")  
o.Init "A", "B"

保存文件并双击它。如果出现错误,则可能是注册的问题,如果没有错误,则应查看 Office 和 VBA 并查看是否缺少某些东西或未正确安装。

另一种选择是添加对 COM 对象的引用并使用早期绑定?我认为您可能需要首先导出类型库,但您应该能够添加引用并简单地新建对象。


在VBScript中也可以正常工作(需要去掉'as object')我刚刚在C# COM对象周围创建了一个VB6 COM DLL包装器。 Excel可以很好地实例化该DLL,并调用其自己的方法,但是当该VB6 DLL依次调用C#对象中的方法时,我再次收到“自动化错误”。 - rc1
看起来问题与 Excel 正在运行有关。 - rc1

0

rc1的说法是正确的,这是一个.NET错误,当Office无法决定使用哪个版本的框架时抛出。然而,Office并不是因为选择太多而抛出异常。Office 2003与.NET 2.0交互存在一个bug。

安装来自Microsoft的修复程序(KB908002)比强制Excel在特定版本的.NET中运行更灵活地解决了这个问题。

另请参阅:http://www.biopdf.com/guide/trouble_shoot_microsoft_office_2003.php


0

这个VBA代码对我有效,我已经在Word和Excel 2003(SP3)中尝试过了。

我不确定你所说的“生产”机器是什么意思。因为这是一个“客户端”应用程序,必须在客户端使用Excel执行。

如果您正在服务器上自动化Excel并通过VBA调用触发此“interop”,那么您会遇到麻烦 :)

假设您所说的“生产”是指用户将使用Excel模板/文档的客户端机器,则有以下几点建议:

  1. 确保您拥有适当的.NET框架
  2. 您拥有Office的最新服务包
  3. 尝试确定是否存在权限问题。

如果您感到冒险,可以使用Microsoft sysinternals网站上的进程资源管理器来查看加载的DLL以及您在哪里遇到错误,并将其与开发计算机上的列表进行比较。

希望这可以帮助您。


谢谢Vyas。是的,通过“生产机器”我只是指装有Office和.NET的终端用户机器,但没有Visual Studio等开发工具。在类似的机器上能否正常运行?你能否分享一些代码?谢谢! - rc1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接