将 C dll 代码编组为 C#
我在 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,但我不完全确定我的问题是什么时候。
I have the following C-code signature in a dll:
extern __declspec(dllexport) unsigned char *
funct_name (int *w, int *h, char **enc, int len, unsigned char *text, int *lp, int *mp, int *ep)
The C function can modify w, h, enc, lp, mp, and ep (though the latter three can be null and it won't do anything.
I'm using the following in 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];
}
I am getting a SystemAccessViolation and I'm not entirely sure when my problem is.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
不要将 StringBuilder 引用传递给采用 char* 的非托管方法。 StringBuilder的内容是unicode(wchar)。
相反,将 StringBuilder 参数替换为 IntPtr 参数,并使用 Marshal.AllocHGlobal 分配适当大小的缓冲区。
另外,我认为 .Net 编组器不支持使用“ref”将 StringBuilder 传递给非托管代码。
Don't pass a StringBuilder reference to a unmanaged method that takes a char*. StringBuilder content is unicode (wchar).
Instead, replace the StringBuilder parameter with and IntPtr parameter and allocate a appropriate size buffer using Marshal.AllocHGlobal.
Also I don't think passing a StringBuilder to unmanaged code using "ref" is supported by the .Net marshaller.
您提到“char **enc”参数可能会被被调用者修改,这可能会导致“SystemAccessViolation”错误。 StringBuilder 可以由被调用者取消引用和修改,前提是它不超过 StringBuilder 的容量。
You mentioned that the 'char **enc' parameter may be modified by the callee, this could be causing the 'SystemAccessViolation' error. A StringBuilder can be dereferenced and modified by the callee, provided it does not exceed the StringBuilders capacity.
StringBuilder
不应使用out
或ref
。从类型为
StringBuilder
的encoding
参数中删除ref
关键字。 这可能是导致您的SystemAccessViolation
的原因。StringBuilder
should not be passed by reference usingout
orref
.Remove the
ref
keyword from theencoding
parameter that is of typeStringBuilder
. That is what is probably causing yourSystemAccessViolation
.我试图在 Unity 中将字符串从 C++ 传递到 C#。 而我得到的只是胡言乱语。 最后,在我看到您的评论 @popcatalin 后,我发现了使用 C# 中的 AllocHGlobal 为字符串分配内存的解决方案。
这是我的 C++ 函数:
这是 Unity 中 C# 脚本的顶部:
这是我在 Unity 中调用该函数的 C# 脚本:
I was trying to pass a string from C++ to C# in Unity. And all I got was gibberish. Finally after I saw your comment @popcatalin I discovered the solution using AllocHGlobal from C# to allocate memory for the string.
This is my C++ function:
This is at the top of the C# script in Unity:
And this is my C# script in Unity calling that function: