C# - 调用传递LPVARIANT的非托管C ++函数

时间:2011-06-21 22:57:10

标签: c# pointers structure unmanaged variant

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

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);

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

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

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

2 个答案:

答案 0 :(得分:1)

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

并将第二个参数声明为“object”,其默认编组是VARIANT。使用“ref”关键字声明它以获取LPVARIANT。

答案 1 :(得分:0)

  

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

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