我在dll中有以下C代码签名:
extern __declspec(dllexport) unsigned char *
funct_name (int *w, int *h, char **enc, int len, unsigned char *text, int *lp, int *mp, int *ep)
C函数可以修改w,h,enc,lp,mp和ep(虽然后三者可以为null,但它不会做任何事情。
我在C#中使用以下内容
[DllImport("iec16022ecc200.dll", EntryPoint = "iec16022ecc200", ExactSpelling = false, CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr CallEncode(
[In,Out,MarshalAs(UnmanagedType.LPArray)] Int32[] width,
[In,Out,MarshalAs(UnmanagedType.LPArray)] Int32[] height,
[In,Out,MarshalAs(UnmanagedType.LPStr)] ref StringBuilder encoding,
int barcodeLen,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder barcode,
IntPtr lenp,
IntPtr maxp,
IntPtr eccp
);
public void Foo (string textToEncode,out int width, out int height) {
StringBuilder text = new StringBuilder(textToEncode);
StringBuilder encoding = new StringBuilder(new string('a', text.Length));
Int32[] w = new Int32[1];
Int32[] h = new Int32[1];
string encodedStr = Marshal.PtrToStringAnsi(CallEncode(w, h, ref encoding, text.Length, text, (IntPtr)0, (IntPtr)0, (IntPtr)0));
width = w[0];
height = h[0];
}
我正在接受SystemAccessViolation,我不确定我的问题何时出现。
答案 0 :(得分:3)
不要将StringBuilder引用传递给带有char *的非托管方法。 StringBuilder内容是unicode(wchar)。
相反,将StringBuilder参数替换为和IntPtr参数,并使用Marshal.AllocHGlobal分配适当大小的缓冲区。
此外,我不认为.Net marshaller支持使用“ref”将StringBuilder传递给非托管代码。
答案 1 :(得分:1)
您提到被调用者可能会修改'char ** enc'参数,这可能会导致'SystemAccessViolation'错误。 StringBuilder可以被被调用者解除引用和修改,前提是它不超过StringBuilders容量。
答案 2 :(得分:1)
StringBuilder
should not be passed by reference using out
or ref
。
//...
[In,Out,MarshalAs(UnmanagedType.LPStr)] ref StringBuilder encoding,
//...
从类型为ref
的{{1}}参数中删除encoding
关键字。这可能是导致您StringBuilder
。
答案 3 :(得分:0)
我试图在Unity中将字符串从C ++传递给C#。而我得到的只是胡言乱语。最后,在我看到你的评论@popcatalin之后,我发现了使用C#的AllocHGlobal为字符串分配内存的解决方案。
这是我的C ++函数:
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API TestString(char* str, int len)
{
strcpy_s(str, len, "C++ String!!! UniversalCpp");
return;
}
这是Unity中C#脚本的顶部:
#if WRCCPP
[DllImport("UniversalWRCCpp", CallingConvention = CallingConvention.Cdecl)]
#else
[DllImport("UniversalCpp", CallingConvention=CallingConvention.Cdecl)]
#endif
private static extern void TestString(IntPtr str, int len);
private IntPtr myPtr = IntPtr.Zero; // Pointer to allocated memory
这是我在Unity中调用该函数的C#脚本:
int sizeInBytes = 100;
myPtr = Marshal.AllocHGlobal(new IntPtr(sizeInBytes));
TestString(myPtr, sizeInBytes);
Debug.Log("ANSI " + Marshal.PtrToStringAnsi(myPtr)); // This prints the correct format