C# 在C中使用ComInterop进行COM对象后期绑定#

C# 在C中使用ComInterop进行COM对象后期绑定#,c#,com,com-interop,idispatch,C#,Com,Com Interop,Idispatch,我有一个COM对象,用于一些简单的数学实用程序。除其他外,它还输出2个接口-IDL如下所示: interface IUnivariateFunction : IDispatch { HRESULT evaluate([in] double a, [out, retval] double* b); }; interface IOneDimSolver : IDispatch { HRESULT Solve([in] double min, [in] double max, [in

我有一个COM对象,用于一些简单的数学实用程序。除其他外,它还输出2个接口-IDL如下所示:

interface IUnivariateFunction : IDispatch
{
    HRESULT evaluate([in] double a, [out, retval] double* b);
};

interface IOneDimSolver : IDispatch
{
    HRESULT Solve([in] double min, [in] double max, [in] double targetAccuracy, [in] LONG maxIterations, [in] IUnivariateFunction* function, [out, retval] double* result);
};
然后,
IOneDimSolver
的实现是:

coclass Brent
{
    [default] interface IOneDimSolver;
};
如果我想在C#中使用此对象,并且我有可用的TypeLibrary,使用此功能非常简单-我可以实现一些函数来解决:

public class CalculatePi : IUnivariateFunction
{
    public double evaluate(double x)
    {
        return x - Math.PI;
    }
}
然后使用它:

var brent = new Brent();
var result = brent.Solve(-10.0, 10.0, 1E-10, 100, new CalculatePi());
这工作非常好,所以没有问题。不过,我还想证明我可以将其用于后期绑定(目前几乎完全是出于学术目的)

看起来正在创建
brent
对象,但调用
InvokeMember
失败,消息为
{“指定的强制转换无效。”}

我猜
CalculatePi
的类型与COM IDispatch机器所期望的任何东西都不兼容,但我只是不确定如何使其工作。任何帮助都会很好

{“指定的强制转换无效。”}

这是一条CLR异常消息,由InvalidCastException生成。这极大地限制了造成这一灾难的可能原因,您知道爆炸的并不是本机代码。在后期绑定代码中没有太多可能的原因。我只能想到一个

最可能的原因是CalculatePi类缺少
[ComVisible(true)]
属性。因此,当CLR试图从对象获取IDispatch接口指针时,它会停止。它在早期绑定的情况下工作,C#编译器可以从类型库中判断它需要生成IUnivariateFunction引用。这是可见的,因为它来自互操作库


应该解决这个问题。但是请记住,IOneDimSolver::Solve()方法实际上与喜欢使用后期绑定的代码类型不兼容。脚本语言不知道如何实现IUnivariateFunction接口,它对它一无所知。您应该声明参数
IDispatch*
,以便任何人都可以调用它。在实现中,使用QueryInterface()获取IUnivariateFunction接口指针。当它成功的时候,你会很高兴,让你可以快速轻松地打电话。但当IDispatch::Invoke()不起作用时,它必须返回IDispatch::Invoke()。如果您不想编写该代码,那么最好不要承诺IDispatch支持并从IUnknown派生接口。

首先,您可以使用带有COM后期绑定的
dynamic
关键字,这要容易得多,比如
dynamic brent=/*create instance*/;var结果brent.Solve(-10.0,10.0,1E-10100,new CalculatePi())。如果这仍然不起作用,IDispatch是如何实现的?IOneDimSolver接口可能没有用,后期绑定将只使用IDispatch。你完全正确,将其创建为
dynamic
更好!不幸的是,我得到了完全相同的错误-我将考虑IDispatch,我不完全确定下一步要尝试什么。你这个绝对的向导@HansPassant,这正是问题所在!非常感谢你!如果你想把它作为一个答案,我很乐意接受:)好答案,好建议-我更新了我的IOneDimSolver界面,改为使用IDispatch*,它按预期工作。谢谢
var brent = Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")));
var result = brent.GetType().InvokeMember("Solve", BindingFlags.InvokeMethod, null, brent, new object[] { -10.0, 10.0, 1E-10, 100, new CalculatePi() });