RegFree COM在C#中工作,但在VBA中不起作用。

10

我目前正在尝试让Excel作为客户端,使用.NET DLL作为服务器,实现无需注册即可使用的COM。目前我只是想试验一下,但遇到了一些问题。

显然,由于我正在使用Excel,所以我不能简单地将客户端清单与可执行文件放在一起,因此我正在使用Microsoft.Windows.ActCtx

我在同一位置拥有客户端清单、程序集清单和DLL。

不幸的是,C#中有效的方法在Excel / VBA中似乎不起作用,我对原因感到困惑。虽然C#测试客户端工作得非常好,但VBA会出现80070002错误,并显示消息Method 'CreateObject' of object 'IActCtx' failed

我有一个.NET DLL(COMTestService.dll),将单个类/接口暴露给COM(COMTestObject / ICOMTestObject),如下所示:

[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("EEE50CDF-D8EC-4F38-B986-C231EC45171E")]
public interface ICOMTestObject
{
    [ComVisible(true)]
    string GetString(int number);
}

[ComVisible(true), ClassInterfaceAttribute(ClassInterfaceType.None), ComDefaultInterface(typeof(ICOMTestObject))]
[Guid("6E54611B-8B56-49E0-9415-E59B0774A4BE")]
public class COMTestObject : ICOMTestObject
{
    public COMTestObject()
    {
    }

    public string GetString(int number)
    {
        return string.Format("The number is: {0}", number);
    }
}

客户端清单(COMTestService_Client.manifest):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly 
    manifestVersion="1.0" 
    xmlns="urn:schemas-microsoft-com:asm.v1" >
    <assemblyIdentity
        name="client"
        version="1.0.0.0" />
    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                name="COMTestService"
                version="1.0.0.0" 
                processorArchitecture="msil" />
        </dependentAssembly>
    </dependency>
</assembly>

程序集清单(COMTestService.manifest):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly 
    manifestVersion="1.0" 
    xmlns="urn:schemas-microsoft-com:asm.v1" >
    <assemblyIdentity 
        name="COMTestService" 
        version="1.0.0.0" 
        processorArchitecture="msil" />
    <clrClass 
        clsid="{6E54611B-8B56-49E0-9415-E59B0774A4BE}" 
        progid="COMTestService.COMTestObject" 
        threadingModel="Both" 
        name="COMTestService.COMTestObject"
        runtimeVersion="v4.0.30319">
    </clrClass>
    <file 
        name="COMTestService.dll"
        hashalg="SHA1">        
    </file>
</assembly>

VBA客户端代码:

Dim actCtx As Object
Set actCtx = CreateObject("Microsoft.Windows.ActCtx")
actCtx.Manifest = "...\COMTestService_Client.manifest"

Dim testObject As Object
Set testObject = actCtx.CreateObject("COMTestService.COMTestObject") 'This line throws... 

Dim text As String
text = thing.GetString(42)

Debug.Print text

C#客户端代码:

var actCtxType = System.Type.GetTypeFromProgID("Microsoft.Windows.ActCtx");
dynamic actCtx = System.Activator.CreateInstance(actCtxType);
actCtx.Manifest = @"...\COMTestService_Client.manifest";

var type = System.Type.GetTypeFromProgID("COMTestService.COMTestObject");
dynamic obj = System.Activator.CreateInstance(type);
dynamic s = obj.GetString(42);

编辑

情况越来越复杂了… 仅仅是为了好玩,我写了一个快速创建COM对象的C#帮助类,并将它注册成可见的,然后通过 public object CreateObject(string manifestPath, string typeName)这样的方法将其传递回去。调用这个方法在C# exe中可以正常工作,但在VBA中调用失败了(80070002,消息:The system cannot find the file specified.)。现在我更加困惑了…

非常感谢任何帮助,如果需要提供更多信息,请告诉我,我会很乐意提供!


传递的清单路径无效,不能使用三个点。您绝对需要完整的路径,因为您无法预测当前工作目录将是什么。 - Hans Passant
抱歉让您感到困惑,那只是一个占位符。完整的路径已经存在,并且是正确的。 - Simon Cowen
2个回答

2

使用“进程监视器(Process Monitor)”,我发现该dll文件在C:/Program Files/Microsoft Office/Office11/中被搜索。我将所有的dll文件移动到该目录下,错误消失了。

顺便说一句,如果有人知道如何让Excel不再在该目录下查找文件,而是在.tlb文件所在的位置查找,请告诉我。(我已经尝试将路径添加到PATH环境变量中)


0

我从未尝试过使用那种技术,而且这些年来我已经做了很多安装。我不禁想知道,为什么不直接注册你的.NET COM可见服务器呢?Regasm倾向于在注册表中创建非常干净和轻量级的COM注册。比旧的非托管DllRegisterServer()方法更加清洁。


不幸的是,这将在没有管理员权限的情况下部署,因此 regasm 将被排除在外... - Simon Cowen
InstallShield MSI项目具有“.NET COM可见”属性,该属性在构建时调用RegAsm以提取COM元数据。对于每个用户的安装,COM键将写入HKCU \ Software \ Classes而不是HKLM \ Software \ Classes。我不明白为什么不能使用RegAsm样式的COM注册。 - Christopher Painter

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