【问题标题】:how to call a C# dll from unmanaged c++ using IDispatch?如何使用 IDispatch 从非托管 c++ 调用 C# dll?
【发布时间】:2023-03-24 20:16:01
【问题描述】:

我有一个需要从非托管 C++ 调用的 C# dll。我遇到的主要问题是我的 c++ 代码对应于一个 excel 加载项,当我在 excel 2007 中安装我的加载项并尝试调用我的 C# dll 时,可以为 excel 2003 和 excel 2007 安装它,它工作得很好,但由于某种原因我仍然无法找到,在 excel 2003 中它崩溃了,excel 向我显示运行时错误消息,并且在调试我的 c++ 代码时,我可以看到代码在尝试时失败创建我的 C# dll 的一个实例,它说即使我注册了 regasm,该类也没有注册。

这是我的 C# 代码:


namespace ManagedDLL
{
    [
        Guid("3C80EE60-D9B8-4daf-89BE-6C7B748F613C"),
        InterfaceType( ComInterfaceType.InterfaceIsDual),
        ComVisible(true)
    ]
    public interface ICalculator
    {
        [DispId(1)]
        int main(string args, IntPtr _handle);
    };


    [
        Guid("5134F342-5B7F-4db2-94F0-F450610419CF"),
        ProgId("myapp.CCOMEntryPoint"),
        ClassInterface(ClassInterfaceType.None),
        ComDefaultInterface(typeof(ICalculator)),
        ComVisible(true)
    ]
    public class COMEntryPoint : ICalculator
    {
        public int main(string args, IntPtr _handle)
        {
            string[] _args = args.Split(new char[] { ':' });

            Program.handle = _handle;
            return Program.Main(_args);
        }
    }
}

在 C++ 中,我所做的是导入使用 regasm 注册 C# dll 时生成的 .tlb 文件,如下所示:


\#import "..\bin\release\ManagedDLL.tlb" raw_interfaces_only
using namespace ManagedDLL;
.
.
.
int callMyDll()
{
    long handle = 0, result = 0;
    BSTR args;

    HRESULT hr = CoInitialize(NULL);

    ICalculatorPtr pICalc(__uuidof(COMEntryPoint));

    pICalc->main(bstrStr, handle, &result);

    return result;
}

但正如我之前提到的,这段代码不适用于 excel 2003,所以我的问题是:

  1. 我在声明 C# dll 的方式上做错了什么,导致我在 excel 2003 中出现问题?
  2. 就像现在一样,我的 C# dll 是否可以被视为 ActiveX 对象?
  3. 如何从 c++ 以另一种方式调用我的 C# dll?例如使用 IDIspatch

谢谢

【问题讨论】:

    标签: c# c++ excel com dll


    【解决方案1】:

    我以前也遇到过类似的问题。我没有从 C++ 调用 C#,但概念是一样的。

    我必须通过 COM 将 .NET dll 加载到主机应用程序中,这看起来就像您正在尝试做的那样。问题是主机应用程序(在您的情况下为 excel)正在加载 .NET 运行时 1.1。我们的 dll 是为 .NET 2.0 编译的。

    可能是 Excel 2003 加载了 1.1 运行时,而 2007 加载了更新的版本。看看这个论坛: Excel selects wrong .NET runtime.

    您也可以通过使用MSBee 来针对 1.1 运行时进行测试,然后尝试在 Excel 2003 中加载您的 dll。

    【讨论】:

    • 是的,问题正是您所怀疑的,excel 正在加载 1.1 运行时,因此您向我展示的那篇文章中建议的修复效果很好,或者还有其他文章谈到同样的问题mcfunley.com/331/… 可能对某人有帮助。
    【解决方案2】:

    我不是 C++ 编码员,所以我不能评论那部分,而是从 C# 方面回答它:

    “我在 我声明我的 C# dll 的方式 导致我在 excel 2003 中出现问题?”

    不,您的属性用法看起来完全正确。干得好。

    "就像现在一样,我的 C# dll 可以 被认为是 ActiveX 对象?”

    通过使用您显示的属性进行编译,然后通过 RegAsm 注册,您已经创建了您的程序集并将其正确地公开给 COM,这正是您想要的。 (术语“ActiveX”通常用于引用 COM 控件,而您的类不是控件。)

    "如何在另一个中调用我的 C# dll 来自c ++的方式?就像使用 IDIspatch 一样 例子。”

    您正在使用[InterfaceType(ComInterfaceType.InterfaceIsDual)] 属性,这意味着该接口通过 IDispatch 暴露给早期绑定和后期绑定。

    简而言之,我不知道这里出了什么问题,所以我会尝试 dequadin 的想法来检查正在加载的 .NET Framework 版本是否等于或高于您正在构建的框架。

    如果不是这样,我唯一能想到的另一件事是您正在直接崩溃,没有可恢复的错误,这向我表明注册之间可能存在某种错位接口与编译调用者的接口。发生这种情况的原因是,如果您更改界面,GUID 不会更改 - 您已通过属性显式设置 GUID - 因此,如果界面发生变化而没有从下到上重新构建和重新注册所有内容,所有的地狱都松散了。因此,如果您以任何方式更改了接口,则需要重新构建 C# 程序集,向 RegAsm 重新注册,然后重新编译引用它的 C++ 加载项。

    不过,这只是我的最佳猜测。如果您使用 same exact 程序集,则不会解释 Excel 2003 与 2007 的问题。简而言之,很难知道哪里出了问题,因为您的 C# 代码看起来 100% 干净。

    -- 迈克

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-07
      • 1970-01-01
      • 1970-01-01
      • 2011-03-04
      • 2011-02-06
      • 2011-05-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多