通过p / invoke使用c#中的XGBoost DLL

我正在尝试使用XGBoost的 dll(libxgboost.dll)来创建一个DMatrix(就像一个2D数组)并获得它有多少列。 它运行正常,直到它在下面的代码中的int cols = ...行抛出System.AccessViolationException

 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错误地执行这些function。 以下是我使用的每个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); 

这是我项目的回购。 我正在使用Visual Studio Enterprise 2015。 它在Windows 10 Pro(64位)上以“调试”模式(以x64为目标)构建。 可以在此处找到libxgboost.dll的x64二进制文件。 虽然链接的repo确实包含libxgboost.dll的副本。

尝试使用似乎由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); }