简体   繁体   English

将C dll代码编组到C#中

[英]Marshalling C dll code into C#

I have the following C-code signature in a dll: 我在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)

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. C函数可以修改w,h,enc,lp,mp和ep(尽管后三个可以为null,并且不会执行任何操作。

I'm using the following in C# 我在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. 我正在获取SystemAccessViolation,但我不确定是什么时候出现问题。

Don't pass a StringBuilder reference to a unmanaged method that takes a char*. 不要将StringBuilder引用传递给采用char *的非托管方法。 StringBuilder content is unicode (wchar). StringBuilder的内容是unicode(wchar)。

Instead, replace the StringBuilder parameter with and IntPtr parameter and allocate a appropriate size buffer using Marshal.AllocHGlobal. 而是将StringBuilder参数替换为和IntPtr参数,并使用Marshal.AllocHGlobal分配适当的大小缓冲区。

Also I don't think passing a StringBuilder to unmanaged code using "ref" is supported by the .Net marshaller. 另外,我不认为.Net marshaller支持使用“ ref”将StringBuilder传递给非托管代码。

StringBuilder should not be passed by reference using out or ref . StringBuilder不应使用outref通过引用传递

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

Remove the ref keyword from the encoding parameter that is of type StringBuilder . StringBuilder类型的encoding参数中删除ref关键字。 That is what is probably causing your SystemAccessViolation . 这可能是导致SystemAccessViolation

You mentioned that the 'char **enc' parameter may be modified by the callee, this could be causing the 'SystemAccessViolation' error. 您提到被调用方可能会修改'char ** enc'参数,这可能会导致'SystemAccessViolation'错误。 A StringBuilder can be dereferenced and modified by the callee, provided it does not exceed the StringBuilders capacity. 被调用方可以取消引用和修改StringBuilder,前提是它不超过StringBuilders的容量。

I was trying to pass a string from C++ to C# in Unity. 我试图在Unity中将字符串从C ++传递给C#。 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. 最后,在看到您的评论@popcatalin后,我发现了使用C#中的AllocHGlobal为字符串分配内存的解决方案。

This is my C++ function: 这是我的C ++函数:

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: 这是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

And this is my C# script in Unity calling that function: 这是我在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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM