如何通过 InvokeHelper 将 variant* 传递给 C#?

Posted

技术标签:

【中文标题】如何通过 InvokeHelper 将 variant* 传递给 C#?【英文标题】:How to pass variant* to C# through InvokeHelper? 【发布时间】:2018-10-17 04:21:33 【问题描述】:

我有一个旧版 c++ 组件。它使用类似性质的 ATL 控件。程序 ID 输入到此组件。它使用 progid 创建 ATL 对象,并使用 dispatchid 使用 InvokeHelper 从 ATL 控件调用方法,如下所示,

DISPID methodDispID;  // dispatchid

long lValue = 0; // first argument long
short nIdx = 1   // second argument short
VARIANT varValue;     // third argument variant

long returnCode = 0;  // return code long

static BYTE parms[] = VTS_I4 VTS_I2 VTS_PVARIANT;

InvokeHelper(methodDispID, DISPATCH_METHOD, VT_ERROR, (void*)&returnCode, parms, &varValue, lValue, nIdx);

在 C++ 中的 ActiveX 方法如下所示,

[id(1), helpstring("method GetValue")] long GetValue(long lValue, short nIdx,VARIANT *varValue);

现在我正在尝试在 C# 中引入 Active X,这意味着我有一个用户控件,我将这个 C# 用户控件的 progid 提供给遗留组件,它创建 C# 用户控件的对象并尝试调用 C# 用户控件的 GeValue 方法定义如下,

C#

interface IMyInterface

         [DispId(1)] Int32 GetValue(System.Int32 lOrder, System.Int16 
             nIdx,object varval); 


class MyClass : IMyInterface

      System.Int32 GetValue(System.Int32 lValue, System.Int16 nIdx,
                                    ref object vCBValue)
      

      

调用C#用户控件的GetValue方法,但抛出异常

System.Runtime.InteropServices.COMException 在 System.RuntimeType.ForwardCallToInvokeMember(System.String, System.Reflection.BindingFlags,System.Object,Int32[], System.Runtime.Remoting.Proxies.MessageData ByRef)

我尝试如下更改 C# 方法定义,但没有任何效果,

System.Int32 GetValue(System.Int32 lValue, System.Int16 nIdx,
                    [MarshalAs(UnmanagedType.Struct)]  ref object varValue);

System.Int32 GetValue(System.Int32 lValue, System.Int16 nIdx,
                     ref IntPtr varValue);

注意:使用 InvokeHelper 调用方法的组件代码对于 C++ 和 C# 用户控件应该相同

【问题讨论】:

您的 GetValue 函数是否定义在接口中?请显示完整的代码。 @SimonMourier 我已经用接口定义更新了问题 您可以尝试在界面中为GetValue添加一个[PreserveSig]属性。 @SimonMourier 设置 [PreserveSig] 没有帮助:( 我们需要一个完整的复制代码才能提供帮助。 【参考方案1】:

如果您尝试重现 c++ COM 代码:

[id(1), helpstring("method GetValue")] 
long GetValue(long lValue, short nIdx,VARIANT *varValue);

...到 c#,然后代替

System.Int32 GetValue(System.Int32 lValue, System.Int16 nIdx, ref object vCBValue);

...应该是:

object GetValue(System.Int32 lValue, System.Int16 nIdx);

这是因为所有 c++ COM 方法都返回 HRESULT(在您的情况下为 long),任何其他返回值都是通过 out 参数。

在 .NET 中,无需定义 HRESULT,我们可以显式返回值,而不是使用 out

【讨论】:

在进行此更改后,也会引发相同的异常,而且我还有一个方法 [id(2), helpstring("method SetValue")] long SetValue(VARIANT* Var,VARIANT* bstrVal,long lOrder,short nIdx);如何在 C# 中制作它? @RajeshSubramanian 你也在 c# 中指定 progids 吗?通常你会在界面上这样做 @@MickyD 是的,我在接口方法中这样设置 DispID,[DispId(1)] Int32 GetValue(System.Int32 lOrder, System.Int16 nIdx,object varval); @RajeshSubramanian 我认为您可以将其放入一个新问题中。听起来好像您在将 c# 类导出到 COM 时遇到了更大的问题

以上是关于如何通过 InvokeHelper 将 variant* 传递给 C#?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 使用 C# DLL。 InvokeHelper 的问题

css Sticky Header che varia allo scroll

PHP HTML / CSS creando varios循环en varias columnas

HTML/CSS creando varios循环en varias columnas

xml Configurar Datasource con DBCP para utilizar Spring JDBC,namedParameters y varias cositas mas

sql MySQL:Conceder特权与una o varias tablas y campos。来自:https://www.sitepoint.com/community/t/mysql-per