1

C#からBorlandC++で記述された.DLLに関数を呼び出そうとしています。その署名は次のとおりです。

extern "C" __declspec(dllexport) ls50errortype __stdcall Ls50P2Open(ls50p2apiconfiginfostruct &configinfo);

C#での対応する呼び出し:

[DllImport("C:\\Lumistar\\LDPS_8x\\Ls50P2_Dll.dll", EntryPoint = "Ls50P2Open", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall, CharSet = CharSet.Ansi, SetLastError = true)]
public static extern void Ls50P2Open(ref ls50p2apiconfiginfostruct configinfo);

対象の構造(ls50p2apiconfiginfostruct)は、ネストされた構造と列挙型(C ++ヘッダーからコピー)で構成されます。

typedef enum
{
    MFMODEL_LS50P1,
    MFMODEL_4422PCI,
    MFMODEL_LS50P2,
    MFMODEL_LS70P2,
    MFMODEL_LS5070,
    MFMODEL_LAST
}ecardmodel;    

typedef enum
{
    CHANNELDEVICE_NONE,
    CHANNELDEVICE_50,
    CHANNELDEVICE_70,
    CHANNELDEVICE_LAST
}ls50p2channeldevicetype;

typedef enum
{
    LS50V2DCARD_NONE, 
    LS50V2DCARD_40V1_10,
    LS50V2DCARD_40V1_20,
    LS50V2DCARD_40V2_10,
    LS50V2DCARD_40V2_20,
    LS50V2DCARD_38,
    LS50V2DCARD_LAST
}ls50p2daughtercardtype;


typedef struct
{
    bool HasDaughterCard;
    ls50p2daughtercardtype DCardType;
    bool SpecialStatusCapable;

    int MaxBitsyncInputs;
    bool HasBitsyncConfidenceLevel;

    bool HasBitsync2ndCh;
    bool SpecialStatusCapable2ndCh;
    bool HasBitsyncConfidenceLevel2ndCh;

    ls50p2daughtercardtype DCardType2ndCh;
    int MaxBitsyncInputs2ndCh;
}ls50p2daughtercardinfostruct;

typedef struct
{
    ecardmodel DeviceModel;
    ls50p2channeldevicetype ChannelDataTypeAry[2];
    ls50p2daughtercardinfostruct DaughterCardInfo;

    bool HasExtendedBertPatterns;

    int FirmwareVersionAry[2];
    int NumPremodFiltersAry[2];
    double Ls50SimPreModFilterKhzAry[2][LS50V2_MAX50SIMPREMODFILTERS];
    double Ls50SimMinFmDeviationKhzAry[2];
    double Ls50SimMaxFmDeviationKhzAry[2];
}ls50p2cardconfigstruct;

typedef struct
{
    unsigned char *DataBuf;
    HANDLE hNewDataRdy;
    DWORD MaxBufLength;
    DWORD CurrentBufLength;
    int NumHeaderBytes;
}ls50p2carddatastruct;

typedef struct
{
    ls50p2cardconfigstruct CardConfigInfo[MAXMFCARDS];
    int Ls50P2CardCount;
    ls50p2carddatastruct DataInfo[MAXMFCARDS][2];
}ls50p2apiconfiginfostruct;

C#の対応する構造体は次のとおりです。

    public enum ecardmodel
    {
        MFMODEL_LS50P1,
        MFMODEL_4422PCI,
        MFMODEL_LS50P2,
        MFMODEL_LS70P2,
        MFMODEL_LS5070,
        MFMODEL_LAST
    }

    public enum ls50p2channeldevicetype
    {
        CHANNELDEVICE_NONE,
        CHANNELDEVICE_50,
        CHANNELDEVICE_70,
        CHANNELDEVICE_LAST
    };

    public enum ls50p2daughtercardtype
    {
        LS50V2DCARD_NONE,
        LS50V2DCARD_40V1_10,
        LS50V2DCARD_40V1_20,
        LS50V2DCARD_40V2_10,
        LS50V2DCARD_40V2_20,
        LS50V2DCARD_38,
        LS50V2DCARD_LAST
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ls50p2daughtercardinfostruct
    {
        public bool HasDaughterCard;
        public ls50p2daughtercardtype DCardType;
        public bool SpecialStatusCapable;

        public int MaxBitsyncInputs;
        public bool HasBitsyncConfidenceLevel;

        public bool HasBitsync2ndCh;
        public bool SpecialStatusCapable2ndCh;
        public bool HasBitsyncConfidenceLevel2ndCh;

        public ls50p2daughtercardtype DCardType2ndCh;
        public int MaxBitsyncInputs2ndCh;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ls50p2cardconfigstruct
    {
        public ecardmodel DeviceModel;
        public ls50p2daughtercardtype[] ChannelDataTypeAry;
        public ls50p2daughtercardinfostruct DaughterCardInfo;

        public bool HasExtendedBertPatterns;

        public int[] FirmwareVersionAry;
        public int[] NumPremodFiltersAry;
        public double[] Ls50SimPreModFilterKhzAry;
        public double[] Ls50SimMinFmDeviationKhzAry;
        public double[] Ls50SimMaxFmDeviationKhzAry;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ls50p2carddatastruct
    {
        public StringBuilder DataBuf;
        public IntPtr hNewDataRdy;
        public uint MaxBufLength;
        public uint CurrentBufLength;
        public int NumHeaderBytes;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ls50p2apiconfiginfostruct
    {
        public ls50p2cardconfigstruct[] CardConfigInfo;
        public int Ls50P2CardCount;
        public ls50p2carddatastruct[,] DataInfo;
    }

関数を呼び出すために使用するC#のコードは次のとおりです。

    ls50p2apiconfiginfostruct lscfg = new ls50p2apiconfiginfostruct();

    lscfg.CardConfigInfo = new ls50p2cardconfigstruct[8];
    for (int i = 0; i < 8; i++)
    {
        lscfg.CardConfigInfo[i].ChannelDataTypeAry = new ls50p2daughtercardtype[2];
    }

    lscfg.DataInfo = new ls50p2carddatastruct[8, 2];

    Ls50P2Open(ref lscfg);

この構造体をC#で作成しようとしましたが、あまり成功していません(列挙型、2D配列、固定サイズのバッファーの問題)。C#でこの構造を作成する正しい方法は何ですか?これは安全でない状況で行う必要がありますか?

何らかの理由で、コードを実行すると次のエラーが発生します。

An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in Library.dll

Additional information: Old format or invalid type library. (Exception from HRESULT: 0x80028019 (TYPE_E_UNSUPFORMAT))
4

2 に答える 2

2

C# の構造はどのように見えますか。StructLayoutAttribute を使用していますか? http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx

オプション sequential を使用して使用できるため、C# 構造体にフィールドを正しい順序で入力するだけで済みます。

于 2012-12-13T21:10:39.423 に答える
1

配列の問題は多かれ少なかれここで答えられていると思います。不適切なマーシャリング: C# 配列から C++ アンマネージ配列へ

受け入れられた答えは、動的に割り当てられた配列を安全にマーシャリングする方法を示しています。

列挙型に関しては、問題が発生することはありません。きれいな 1:1 マッピングがあります。実際、この msdn の投稿で説明されているように実行します。http://blogs.msdn.com/b/abhinaba/archive/2007/08/27/sharing-enums-across-c-and-c.aspx

すべての列挙型を .cs ファイルで定義し、それを両方のプロジェクトに含めるだけで、すべてが正常に機能します。

于 2012-12-13T21:15:38.880 に答える