3

あはは、この質問はスタック オーバーフロー全体にあるため、既に 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 プロジェクトとして実行しようとすると、PInvoke エラーが発生します。呼び出しを StdCall に変更しても (予想どおり)、同じエラーが発生します。

何かご意見は?構造体が何らかの形で干渉していると推測していますが、このようなインポートを使用することは私にとって一般的なタスクではないため、これは盲目的な推測です。グーグルに聞いて、ここでもっと深く調べてみましょう。

編集:これが役立つ場合、参照として渡される2つの構造体を次に示します:

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

    };

EDIT関連する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 エラーで失敗します。

4

1 に答える 1

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

呼び出し規約を試していないことに注意してください。実際のコードでテストする必要があるかもしれません。

于 2013-03-06T19:03:47.323 に答える