簡體   English   中英

將C#結構傳遞給非托管C ++ DLL時出現SafeArrayTypeMismatchException

[英]SafeArrayTypeMismatchException when passing c# struct to unmanaged C++ DLL

嗨,我是C#和C ++編程的新手,正在嘗試在C#項目(.NET 3.5)中使用不受管理的C ++ dll。 我陷入了這個錯誤:

System.Runtime.InteropServices.SafeArrayTypeMismatchException:指定的數組不是預期的類型。

這是DLL的頭文件

#ifdef FUNCTIONLIB_EXPORTS
#define FUNCTIONLIB_API __declspec(dllexport)
#else
#define FUNCTIONLIB_API __declspec(dllimport)
#endif
typedef struct _FunctionOpt 
{
    char                UserName[32];
    char                Password[32];
    char                ServerIP[128];
    int                 ServerPort;
    int                 Index;          
    char                TargetSubChannel;
    long                Timeout;
    char                Filepath[256];
    bool                isFirst;        
    DWORD               SyncTime;               
    char                *pOutBuf;               
    int                 OutBufSize;
    unsigned short      OutImgResW;
    unsigned short      OutImgResH;

}STFUNCTIONOPT, *PSTFUNCTIONOPT;

FUNCTIONLIB_API int FunctionLib_Snapshot( PSTFUNCTIONOPT pstFunctionOpt ); 

我無權訪問C ++代碼,因此只能更改以下C#代碼。 我的相關代碼如下:

    public unsafe struct PSTFUNCTIONOPT            
    {
        public char[] UserName;
        public char[] Password;
        public char[] ServerIP;
        public int ServerPort;
        public int Index;                      
        public char TargetSubChannel;              
        public long Timeout;              
        public char[] Filepath;
        public bool isFirst;               
        public uint SyncTime;                       
        public char *pOutBuf;   // example C++ usage: myStruct.pOutBuf = (char*)malloc(1920 * 1080 * 3);
        public int OutBufSize;
        public ushort OutImgResW;
        public ushort OutImgResH;
    }

    // need to use dumpbin to get entrypoint name due to c++ mangling
    [DllImport(@"C:\Location\To\Project\bin\FunctionLibLib.dll", EntryPoint = "?FunctionLib_Snapshot@@YAHPAU_FunctionOpt@@@Z")]
    public static extern int FunctionLib_Snapshot(PSTFUNCTIONOPT pstFunctionOpt);

    public unsafe int FunctionLib_Run()
    {
        PSTFUNCTIONOPT stFunctionOpt = new PSTFUNCTIONOPT();

        stFunctionOpt.UserName = ("uname").ToCharArray();
        stFunctionOpt.Password = ("pword").ToCharArray();
        stFunctionOpt.ServerIP = ("192.168.1.1").ToCharArray();
        stFunctionOpt.ServerPort = 80;
        stFunctionOpt.Index = 255;
        stFunctionOpt.Timeout = 15000;
        stFunctionOpt.Filepath = ("c:\\temp\\test.jpg").ToCharArray();
        stFunctionOpt.isFirst = true;
        stFunctionOpt.SyncTime = 0;
    //stFunctionOpt.pOutBuf = new char*[10000];     // not sure how to do this yet
        stFunctionOpt.OutBufSize = 10000;

        // get result from DLL 
        return FunctionLib_Snapshot(stFunctionOpt);
    }

如何將結構正確傳遞給此非托管DLL? 該錯誤似乎很簡單,但我無法縮小問題的范圍。 任何幫助表示贊賞!

幾個問題:

    public char[] UserName;

需要將其編組為嵌入的字符串:

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string UserName;

對其他這樣聲明的字段重復該操作。

    public char *pOutBuf;   // example C++ usage: myStruct.pOutBuf = (char*)malloc(1920 * 1080 * 3);

目前尚不清楚C ++函數是分配該緩沖區還是應該由客戶端代碼執行此操作。 如果是前者,那么您有一個大問題,則無法調用free()函數再次釋放緩沖區。 您唯一的希望是C#代碼應該分配它,這並非沒有可能。 在這種情況下是:

    public byte[] pOutBuf;
    ...
    stFunctionOpt.pOutBuf = new byte[10000];
    stFunctionOpt.OutBufSize = stFunctionOpt.pOutBuf.Length;

pinvoke聲明錯誤:

[DllImport(@"C:\Location\To\Project\bin\FunctionLibLib.dll", EntryPoint = "?FunctionLib_Snapshot@@YAHPAU_FunctionOpt@@@Z")]
public static extern int FunctionLib_Snapshot(PSTFUNCTIONOPT pstFunctionOpt);

參數為ref PSTFUNCTIONOPT pstFunctionOpt 請從結構名稱中刪除P,它不是指針類型。 避免對DLL的路徑進行硬編碼,否則將無法在用戶的計算機上正常工作。 只要確保您在構建輸出目錄中有DLL的副本即可。

我認為您在結構定義中缺少了幾件事

  • 內存中struct的布局在c ++中是不同的,因此您需要向結構中添加[StructLayout(LayoutKind.Sequential)]屬性
  • 在C ++中,您具有固定長度的char數組,因此,您還需要在c#中使用屬性[MarshalAs(UnmanagedType.ByValTStr, SizeConst = your_array_lenght)] ,此外,封送處理程序將處理字符串和char數組之間的轉換。

然后,您的結構定義應類似於

[StructLayout(LayoutKind.Sequential)]
public struct PSTFUNCTIONOPT            
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string UserName;
    ...
    [MarshalAs(UnmanagedType.LPStr)]
    public string pOutBuf;  
}

有關更多信息,請訪問http://msdn.microsoft.com/zh-cn/library/s9ts558h.aspx

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM