如何使用IDispatch从非托管c ++调用C#dll?

时间:2009-09-24 18:53:22

标签: c# c++ excel com dll

我需要从非托管C ++调用C#dll。我遇到的主要问题是我的c ++代码对应于excel加载项,可以安装excel 2003和excel 2007,当我在excel 2007中安装我的加载项时,我尝试调用我的C#dll,它运行得很好,但由于某种原因,我仍然无法找到,在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
  4. 由于

2 个答案:

答案 0 :(得分:3)

我之前遇到过类似的问题。我不是用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。

答案 1 :(得分:0)

我不是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 ++加载项。

这只是我最好的猜测。如果您为每个问题使用相同的程序集,则不解释Excel 2003与2007年的问题。简而言之,很难知道什么是错的,因为你的C#代码看起来很干净。

- 迈克