2016-11-11 70 views
0

我試圖使用XGBoost's DLL(libxgboost.dll)創建DMatrix(這就像一個二維數組),並把它多少列了。它運行正常,直到它在下面的代碼拋出一個System.AccessViolationExceptionint cols = ...行:使用XGBoost DLL從C通過P#/調用

using System; 
using System.Runtime.InteropServices; 

namespace basicXgboost 
{ 
    class Program 
    { 
    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)] 
    public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, IntPtr outputPtr); 

    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)] 
    public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr); 

    static void Main(string[] args) 
    { 
     IntPtr dmatrixPtr = Marshal.AllocHGlobal(1000000); 
     IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10); 

     int result = XGDMatrixCreateFromFile("../../libs/test.txt", 0, dmatrixPtr); 
     int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr); 

     Marshal.FreeHGlobal(dmatrixPtr); 
     Marshal.FreeHGlobal(dmatrixColumnsPtr); 
    } 
    } 
} 

爲什麼訪問非託管內存XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr)事業System.AccessViolationException分配呢?

一種可能性是,我使用的PInvoke錯誤地實現這些功能。下面是我使用的每個DLL函數的定義:

XGDMatrixCreateFromFile()

/*! 
* \brief load a data matrix 
* \param fname the name of the file 
* \param silent whether print messages during loading 
* \param out a loaded data matrix 
* \return 0 when success, -1 when failure happens 
*/ 
XGB_DLL int XGDMatrixCreateFromFile(const char *fname, 
            int silent, 
            DMatrixHandle *out); 

XGDMatrixNumCol()

/*! 
* \brief get number of columns 
* \param handle the handle to the DMatrix 
* \param out The output of number of columns 
* \return 0 when success, -1 when failure happens 
*/ 
XGB_DLL int XGDMatrixNumCol(DMatrixHandle handle, 
          bst_ulong *out); 

Here是我的項目的回購協議。我正在使用Visual Studio Enterprise 2015。它在Windows 10 Pro(64位)上以「調試」模式(目標x64)構建。可以找到libxgboost.dll的x64二進制文件here。雖然鏈接的回購確實包含libxgboost.dll的副本。

+0

不要讓我們通過場外代碼打獵。即使如此,我們如何才能知道每個功能的要求是什麼?你有沒有可用的示例C++代碼。 –

+0

對不起。我不想通過複製粘貼所有C++定義來使問題時間過長。你能澄清你的意思是什麼樣的C + +代碼?我正在用C#編寫這個代碼,一切都到了「int cols = ...」這行似乎正在工作。 – cycloidistic

+0

這個問題沒有任何重要的細節。 –

回答

1

嘗試使用似乎由DLL使用的調用約定Cdecl。

此外,XGDMatrixCreateFromFile功能的簽名是錯誤的。期望的參數不是指向你分配的某個內存的指針,但該函數將自己分配內存,然後將該指針作爲輸出參數返回。

請嘗試下面的代碼。請注意,在XGDMatrixCreateFromFile函數中使用outputPtr參數中的out關鍵字。

[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr); 

[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr); 

static void Main(string[] args) 
{ 
    IntPtr dmatrixPtr; 
    IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10); 

    int result = XGDMatrixCreateFromFile("C:\\dev\\libs\\xgboost\\demo\\data\\agaricus.txt.test", 0, out dmatrixPtr); 
    int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr); 

    Marshal.FreeHGlobal(dmatrixColumnsPtr); 
} 

當這個作品,你就可以還簡化了呼叫是通過使用ulong數據類型來獲得的列數:

[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr); 

[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, out ulong dmatrixColumnsPtr); 

static void Main(string[] args) 
{ 
    IntPtr dmatrixPtr; 
    ulong dmatrixColumns; 

    int result = XGDMatrixCreateFromFile("C:\\dev\\libs\\xgboost\\demo\\data\\agaricus.txt.test", 0, out dmatrixPtr); 
    int cols = XGDMatrixNumCol(dmatrixPtr, out dmatrixColumns); 
} 
+0

剛剛試過了,我得到了同樣的錯誤:(雖然,你可以把這個答案在我的[新問題](http://stackoverflow.com/questions/40580825/why-does-access-unmanaged-memory-cause-a-system-accessviolationexception)其中我以一種更好的方式改寫了這個問題? – cycloidistic

+0

我一定會在將來做到這一點。謝謝你讓我知道:) – cycloidistic

+0

添加'out'關鍵字並更改聲明爲我解決了它。謝謝@NineBerry :)出於好奇,爲什麼添加'out'修復這個問題? – cycloidistic