Я написал базовую библиотеку C++, которая получает данные с сервера OPC UA и форматирует его в массив строк (char **). Я подтвердил, что он работает автономно, но теперь я пытаюсь вызвать его из программы на C#, используя библиотеки DLL/pInvoke и сталкиваясь с серьезными ошибками памяти.(C#) AccessViolationException при получении char ** из C++ DLL
Мой C# главная:
List<String> resultList = new List<string>();
IntPtr inArr = new IntPtr();
inArr = Marshal.AllocHGlobal(inArr);
resultList = Utilities.ReturnStringArray(/*data*/,inArr);
C# Вспомогательные функции:
public class Utilities{
[DllImport(//DllArgs- confirmed to be correct)]
private static extern void getTopLevelNodes(/*data*/, IntPtr inArr);
public static List<String> ReturnStringArray(/*data*/,IntPtr inArr)
{
getTopLevelNodes(/*data*/,inArr); // <- this is where the AccessViolationException is thrown
//functions that convert char ** to List<String>
//return list
}
И, наконец, мой C++ Деятельность по осуществлению DLL:
extern "C" EXPORT void getTopLevelNodes(*/data*/,char **ret){
std::vector<std::string> results = std::vector<std::string>();
//code that fills vector with strings from server
ret = (char **)realloc(ret, sizeof(char *));
ret[0] = (char *)malloc(sizeof(char));
strcpy(ret[0], "");
int count = 0;
int capacity = 1;
for (auto string : results){
ret[count] = (char*)malloc(sizeof(char) * 2048);
strcpy(ret[count++], string.c_str());
if (count == capacity){
capacity *= 2;
ret = (char **)realloc(ret, sizeof(char *)*capacity + 1);
}
}
Что это должно сделать это, инициализировать список чтобы конечный результат и IntPtr были заполнены как char ** с помощью библиотеки C++ DLL, которая затем обрабатывается обратно C# и отформатирован в список. Однако AccessViolationException бросается каждый раз, когда я вызываю getTopLevelNodes из C#. Что я могу сделать, чтобы исправить эту проблему памяти? Это лучший способ передать массив строк через interop?
Спасибо заранее
Edit: Я до сих пор ищет больше ответов, если есть более простой способ реализовать массив строк Interop между C# и DLL, пожалуйста, дайте мне знать!
Не ставить это как ответ, поскольку я не уверен и не могу его протестировать, но вы пытались использовать 'IntPtr []' вместо 'IntPtr', поскольку вы, в некотором смысле, передаете массив указателей, а не только один указатель. Кроме того, как замечание, я считаю, что у вас есть утечка памяти из 1 символа для вашего первого элемента массива, так как вы malloc место для него, а затем вызовите malloc снова на первой итерации вашего цикла. – pstrjds
@pstrjds спасибо, я исправлю это –
Я не знаю вашу ситуацию, но можно ли создать обертку C++/CLI вокруг вашего C++-вызова? Тогда у вас может быть класс, который делает вызов, который заполняет вектор, а затем выталкивает эти данные в структуру .Net для потребления на вашей стороне C#. – pstrjds