将 C dll 代码编组为 C#

发布于 2024-07-18 04:22:15 字数 1482 浏览 6 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

长梦不多时 2024-07-25 04:22:15

不要将 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.

青芜 2024-07-25 04:22:15

您提到“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.

橙幽之幻 2024-07-25 04:22:15

StringBuilder 不应使用 outref

    //...
    [In,Out,MarshalAs(UnmanagedType.LPStr)] ref StringBuilder encoding,
    //...

从类型为 StringBuilderencoding 参数中删除 ref 关键字。 这可能是导致您的 SystemAccessViolation 的原因。

StringBuilder should not be passed by reference using out or ref.

    //...
    [In,Out,MarshalAs(UnmanagedType.LPStr)] ref StringBuilder encoding,
    //...

Remove the ref keyword from the encoding parameter that is of type StringBuilder. That is what is probably causing your SystemAccessViolation.

说不完的你爱 2024-07-25 04:22:15

我试图在 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

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:

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API TestString(char* str, int len)
{
    strcpy_s(str, len, "C++ String!!! UniversalCpp");
    return;
}

This is at the top of the C# script in Unity:

#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

And this is my C# script in Unity calling that function:

int sizeInBytes = 100;
myPtr = Marshal.AllocHGlobal(new IntPtr(sizeInBytes));
TestString(myPtr, sizeInBytes);
Debug.Log("ANSI " + Marshal.PtrToStringAnsi(myPtr)); // This prints the correct format
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文