(c#)从c dll获取char **时的accessViolationException
(C#) AccessViolationException when getting char ** from C++ DLL
我已经写了一个基本的C 库,该库从OPC UA服务器获取数据,并将其格式化为一系列字符串(char **)。我已经确认它是独立的,但是现在我试图使用DLL/PINVOKE从C#程序调用它并陷入严重的内存错误。
我的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则由C DLL填充为char **,然后将其重新处理为C#并格式化为列表。但是,每次我从C#调用GetToplevelnodes时,都会抛出AccessVioLationException。我该怎么办来解决此内存问题?这是通过Interop通过一系列字符串的最佳方法吗?
预先感谢您
编辑:我仍在寻找更多答案,如果有一种更简单的方法可以实现C#和DLL之间的字符串数组,请让我知道!
方法1-高级结构编组。
与编组列表相反,尝试创建这样的C#结构:
[StructLayout(LayoutKind.Sequential, Pack = 2)]
public struct StringData
{
public string [] mylist; /* maybe better yet byte[][] (never tried)*/
};
现在在C#Marshall中:
IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(StringData)); // Into Unmanaged space
获取指向结构的指针。
StringData theStringData = /*get the data*/;
Marshal.StructureToPtr(theStringData, pnt, false);
// Place structure into unmanaged space.
getTopLevelNodes(/* data */, pnt); // call dll
theStringData =(StringData)Marshal.PtrToStructure(pnt,typeof(StringData));
//get structure back from unmanaged space.
Marshal.FreeHGlobal(pnt); // Free shared mem
现在在CPP中:
#pragma pack(2)
/************CPP STRUCT**************/
struct StringDataCpp
{
char * strings[]
};
和功能:
extern "C" EXPORT void getTopLevelNodes(/*data*/,char *ret){ //just a byte pointer.
struct StringDataCpp *m = reinterpret_cast<struct StringDataCpp*>(ret);
//..do ur thing ..//
}
我也使用了这种模式,其结构也更为复杂。关键是,您只是通过c#的字节复制字节,然后通过c 的字节来解释字节。
"包装"是这里的关键,以确保结构在内存中以相同的方式对齐。
方法2-带有fixed
//USE YOUR LIST EXCEPT List<byte>.
unsafe{
fixed (byte* cp = theStringData.ToArray)
{
getTopLevelNodes(/* data */, cp)
/////...../////
//SNIPPET TO CONVERT STRING ARRAY TO BYTE ARRAY
string[] stringlist = (/* get your strings*/);
byte[] theStringData = new stringlist [stringlist .Count()];
foreach (string b in parser)
{
// ADD SOME DELIMITER HERE FOR CPP TO SPLIT ON?
theStringData [i] = Convert.ToByte(stringlist [i]);
i++;
}
现在
CPP只是收到char*。您现在需要一个定界符来分开字符串。请注意,您的字符串可能具有分配仪' 0'已经使用替换算法将其替换为';''或者,使用strtok with';'作为定界符或使用Boost!
或者,如果可能,请尝试制作字节指针阵列。
Byte*[i] theStringStartPointers = &stringList[i]/* in a for loop*/
fixed(byte* *cp = theStringStartPointers) /// Continue
这种方式要简单得多。unsafe
块允许fixed
块,固定块确保C#内存管理机制不会移动该数据。
- 使用c#访问c++dll中带有char*参数的函数时发生AccessViolationException
- 对象初始化后在C++中显示 char 数组时的异常行为
- 为什么将指针重新分配给 1D 数组的 char 时显示错误,但 2D 数组工作正常?
- 当我们已经有 char[] 时,在 c++ 中字符串的必要性是什么?
- 试图使用strCMP时的char转换错误
- 试图创建动态分配的char数组时的分割故障
- 当我释放由CFFI生成的DLL分配的char*时,为什么我的应用程序会崩溃
- 使用char*时,替换了不弃用的strcpy/strcat
- 当返回一系列字符或指针到char文字时的区别
- 初始化char数组和具有整数文字的char时的差异
- (c#)从c dll获取char **时的accessViolationException
- 将字符串转换为c 中的char*时,畸形输出
- 尝试将const char *转换为lptstr时的链接器错误
- 转换char*时的值不同
- 为什么当我们反转此函数中的字符串时,char *str 的指针没有改变?
- 错误:将"char*"分配给"char [20]"时的类型不兼容
- 将QString转换为const-char*时的不可预测的运行时行为
- 改变c++中char *const所指向的数据时的访问冲突
- 当我尝试编写'const char *'时,C ++给了我标准的字符串/相关数据而不是二进制数据
- 将二进制文件读取到向量"unsigned char"时的模板参数是什么