对PInvoke的调用使堆栈失去平衡...即使使用Cdecl,dll导入也会失败

时间:2013-03-06 18:45:52

标签: c# .net-4.0 dllimport

啊哈,这个问题已经遍布堆栈溢出所以我已经开始添加CallingConvention = CallingConvention.Cdecl,这对我必须导入的其他库工作得很好,但在这种情况下,没有任何变化,它仍然失败使用相同的错误消息。

这个原始代码来自一个.net 3.5项目并且工作得很好:

[DllImport("Compiled DSP.dll")]
private static extern int fnGetConfigParam(int nID, ref stParamInt pstParam);

[DllImport("Compiled DSP.dll")]
private static extern int fnGetConfigParam(int nID, ref stParamFloat pstParam);

新项目是一个尝试调用同一个库的.net 4.0项目。我已经添加了调用约定:

[DllImport("Compiled DSP.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int fnGetConfigParam(int nID, ref stParamInt pstParam);

[DllImport("Compiled DSP.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int fnGetConfigParam(int nID, ref stParamFloat pstParam);

两种ref类型都是结构。当我尝试运行调用此函数作为3.5项目的相同代码时,即使我将调用更改为StdCall(正如预期的那样),我也会收到PInvoke错误。我得到相同的错误。

有什么想法?我猜这个结构在某种程度上会干扰但是使用这样的导入对我来说不是一个常见的任务,所以这是一个盲目的猜测。是时候问谷歌了,在这里深入探讨。

编辑 :如果这很有用,以下是作为参考传递的两个结构:

stParamInt:

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    private struct stParamInt           
    {
        public uint unID;
        public int nValue;
        public int nValueMin;
        public int nValueMax;
        public int nValueDef;
        public int nUnitsType;
        public int nUnits;

        public byte[] GetBytes()
        {
            byte[] result = new byte[0];
            List<byte> buf = new List<byte>();
            buf.AddRange(BitConverter.GetBytes(unID));
            buf.AddRange(BitConverter.GetBytes(nValue));
            buf.AddRange(BitConverter.GetBytes(nValueMin));
            buf.AddRange(BitConverter.GetBytes(nValueMax));
            buf.AddRange(BitConverter.GetBytes(nValueDef));
            buf.AddRange(BitConverter.GetBytes(nUnitsType));
            buf.AddRange(BitConverter.GetBytes(nUnits));
            result = buf.ToArray();
            return result;
        }

        public stParamInt(byte[] buf)
        {
            unID = BitConverter.ToUInt32(buf, 0);
            nValue = BitConverter.ToInt32(buf, 4);
            nValueMin = BitConverter.ToInt32(buf, 8);
            nValueMax = BitConverter.ToInt32(buf, 12);
            nValueDef = BitConverter.ToInt32(buf, 16);
            nUnitsType = BitConverter.ToInt32(buf, 20);
            nUnits = BitConverter.ToInt32(buf, 24);
        }
    };

stParamFloat:

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    private struct stParamFloat                 
    {
        public uint unID;
        public float fValue;
        public float fValueMin;
        public float fValueMax;
        public float fValueDef;
        public int nUnitsType;
        public int nUnits;

        public byte[] GetBytes()
        {
            byte[] result = new byte[0];
            List<byte> buf = new List<byte>();
            buf.AddRange(BitConverter.GetBytes(unID));
            buf.AddRange(BitConverter.GetBytes(fValue));
            buf.AddRange(BitConverter.GetBytes(fValueMin));
            buf.AddRange(BitConverter.GetBytes(fValueMax));
            buf.AddRange(BitConverter.GetBytes(fValueDef));
            buf.AddRange(BitConverter.GetBytes(nUnitsType));
            buf.AddRange(BitConverter.GetBytes(nUnits));
            result = buf.ToArray();
            return result;
        }

        public stParamFloat(byte[] buf)
        {
            unID = BitConverter.ToUInt32(buf, 0);
            fValue = BitConverter.ToSingle(buf, 4);
            fValueMin = BitConverter.ToSingle(buf, 8);
            fValueMax = BitConverter.ToSingle(buf, 12);
            fValueDef = BitConverter.ToSingle(buf, 16);
            nUnitsType = BitConverter.ToInt32(buf, 20);
            nUnits = BitConverter.ToInt32(buf, 24);
        }

    };

编辑 我设法在相关的dll中挖掘出签名,它是使用以下方法签名的C ++非托管代码:

COMPILEDDSP_API int fnGetConfigParam(int nID, struct stPint *pstParam)
{
    return CONFIG_GetSetConfigParam(GET_PARAM, nID, pstParam, &g_stActiveCfg, sizeof(struct stActiveConfig)/sizeof(struct stPint), NULL);
}

不幸的是,对于我来说,我并不是特别流利的标准C ++函数,但签名看起来很好。

编辑 我发现如果我只是从我的垃圾箱中构建并运行它,它就可以正常工作。如果我尝试通过visual studio在调试模式下运行,它会因此PInvoke错误而失败。

1 个答案:

答案 0 :(得分:1)

看看这些答案

您可以使用ref传递IntPtr个结构,导入将是

[DllImport("Compiled DSP.dll")]
private static extern int fnGetConfigParam(int nID, IntPtr pstParam);

和测试

var sizeParamInt=Marshal.SizeOf(typeof(stParamInt));
var marshalParamInt=Marshal.AllocHGlobal(sizeParamInt);
fnGetConfigParam(123, marshalParamInt);
var paramInt=(stParamInt)Marshal.PtrToStructure(marshalParamInt, typeof(stParamInt));
Marshal.FreeHGlobal(marshalParamInt);

请注意,我没有尝试调用约定,您可能需要使用实际代码进行测试。