【问题标题】:C# - Calling unmanaged C++ function passing LPVARIANTC# - 调用传递 LPVARIANT 的非托管 C++ 函数
【发布时间】:2011-06-21 22:57:10
【问题描述】:

我想从我的托管代码中调用以下函数:

short LS_LoadConfig(LS_ID SensorID,LPVARIANT varConfigPathFile,BOOL bInit)

这是我在 C# 类中声明 extern 函数的方式:

[DllImport("LineSensor.dll", EntryPoint = "#16")]
private static extern Int16 LS_LoadConfig(
        Int16 deviceId,
        IntPtr variantFilePath,
        int init);

这就是我如何创建 VARIANT 实例并获得指向它的指针。然后我调用C#函数:

string filepath = @"C:\Windows\ ...";
IntPtr variantFilePath = Marshal.AllocCoTaskMem(200);
Marshal.GetNativeVariantForObject(filepath, variantFilePath);
LS_LoadConfig(device.Id, variantFilePath, initLineSensor);

问题是我不断收到错误消息,例如“调用 LS_LoadConfig 函数使堆栈不平衡,请检查参数是否与非托管签名匹配”。

问题似乎是由第二个参数“variantFilePath”引起的,就像它没有正确编组并且它在非托管堆上的大小不对应于地址之一(在我的例子中是 32 位)。我尝试将 C# 函数签名中的类型从 IntPtr 更改为 int,如下所示:

[DllImport("LineSensor.dll", EntryPoint = "#16")]
    private static extern Int16 LS_LoadConfig(
        Int16 deviceId,
        int variantFilePath,
        int init);

我尝试调用传递随机数的函数,结果稍微好一点,我刚刚收到一个错误“内存访问冲突”。显然是因为随机数不是有效地址。

有人知道这个问题的解决方法吗?

感谢您提供任何有用的信息。

【问题讨论】:

    标签: c# pointers structure unmanaged variant


    【解决方案1】:

    您创建的访问冲突并不好。它还可以防止生成 MDA 警告。除了参数类型错误之外,int16 看起来很奇怪,最有可能的问题是由 CallingConvention 引起的。试试 StdCall。

    并将第二个参数声明为“对象”,它的默认封送处理是一个 VARIANT。使用“ref”关键字声明它以获得 LPVARIANT。

    【讨论】:

      【解决方案2】:

      “调用 LS_LoadConfig 函数使堆栈不平衡,检查参数是否与非托管签名匹配”。

      这通常意味着您在本机代码和托管代码之间使用了冲突的调用约定。 C# 默认使用 stdcall,而 c/c++ 使用 cdecl。尝试指定 CallingConvention = CallingConvention.Cdecl。

      【讨论】:

      • 问题是调用约定必须设置为 Cdecl。所以 [DllImport("LineSensor.dll", EntryPoint = "#16", CallingConvention=CallingConvention.Cdecl)] 修复了一切。 @Hans 传递 ref 对象也确实与传递 LPVARIANT 相同,但比我的解决方案更优雅。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-24
      • 1970-01-01
      • 1970-01-01
      • 2020-08-26
      • 2011-09-15
      • 1970-01-01
      相关资源
      最近更新 更多