首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MarshalAs(UnmanagedType.LPStr) -如何将utf-8字符串转换为char*

MarshalAs(UnmanagedType.LPStr) -如何将utf-8字符串转换为char*
EN

Stack Overflow用户
提问于 2012-11-08 12:30:03
回答 4查看 19.4K关注 0票数 14

题目基本上就是我想问的问题:

[MarshalAs(UnmanagedType.LPStr)] -如何将utf-8字符串转换为char*?

当我试图在c#和c++ dll之间进行通信时,我使用上面的行;更具体地说,在以下几个方面之间:

代码语言:javascript
运行
复制
somefunction(char *string) [c++ dll]

somefunction([MarshalAs(UnmanagedType.LPStr) string text) [c#]

当我将utf-8文本(scintilla.Text)通过c#发送到我的c++ dll中时,我在VS 10调试器中显示:

  1. c#字符串已成功转换为char*
  2. 得到的char*正确地反映了手表窗口中相应的utf-8字符(包括韩语中的位)。

下面是截图(有更多细节):

如您所见,initialScriptText[0]返回单个byte(char):'B‘,char* initialScriptText的内容在VS监视窗口中正确显示(包括韩语)。

通过char指针,英语似乎被保存为每个char的一个byte,而韩语似乎被保存为每个char的两个字节。(截图中的韩语单词是3个字母,因此以6个字节保存)

这似乎表明每个“字母”不是保存在相同大小的容器中,而是根据语言的不同而不同。(可能提示类型?)

我试图在纯c++中实现相同的结果:读取utf-8文件并将结果保存为char*

下面是我尝试读取utf-8文件并在c++中转换为c++的一个例子:

意见:

  1. wchar_t*转换到char*时的视觉损失
  2. 由于结果,s8正确地显示了字符串,我知道我已经成功地将wchar_t*中的utf-8文件内容转换为char*
  3. 由于“结果”保留了我直接从文件中获取的字节,但我得到的结果与通过c#获得的结果不同(我使用了相同的文件),因此我得出结论,c#封送处理通过其他一些过程将文件内容进一步修改为char*

(截图也显示了我在使用wcstombs方面的严重失败)

注意:我使用的是utf8头(http://utfcpp.sourceforge.net/)

请纠正我的代码/观察中的任何错误。

我希望能够模仿我通过c#法警的结果,在经历了所有这些之后,我意识到我完全被困住了。有什么想法吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-11-08 13:45:47

MarshalAs(UnmanagedType.LPStr) -如何将utf-8字符串转换为char*?

没有。在托管代码中没有所谓的"utf-8字符串“,字符串总是用utf-16编码。从和到LPStr的封送处理都是使用默认的系统代码页完成的。这使您在调试器中看到韩文符号相当引人注目,除非您使用代码页949。

如果与utf-8互操作是一个困难的要求,那么您需要在pinvoke声明中使用byte[]。并使用System.Text.Encoding.UTF8来回转换。使用其GetString()方法将byte[]转换为字符串,使用GetBytes()方法将字符串转换为byte[]。如果可能的话,可以在本机代码中使用wchar_t[]来避免这一切。

票数 16
EN

Stack Overflow用户

发布于 2018-03-21 03:34:23

虽然其他答案是正确的,但在.NET 4.7中有一个重大的发展。现在有一个选项可以实现UTF-8所需的功能:UnmanagedType.LPUTF8Str。我试过了,它的工作原理就像瑞士的天文钟,就像它听起来的那样。

事实上,我甚至在一个参数中使用了MarshalAs(UnmanagedType.LPUTF8Str),在另一个参数中使用了MarshalAs(UnmanagedType.LPStr)。也很管用。下面是我的方法(接收字符串参数并通过参数返回字符串):

[DllImport("mylib.dll", ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern void ProcessContent([MarshalAs(UnmanagedType.LPUTF8Str)]string content, [MarshalAs(UnmanagedType.LPUTF8Str), Out]StringBuilder outputBuffer,[MarshalAs(UnmanagedType.LPStr)]string settings);

谢谢微软!又一件讨厌的事消失了。

票数 14
EN

Stack Overflow用户

发布于 2020-11-18 15:45:24

如果使用ICustomMarshaler框架早于4.7,则可以使用.NET。

代码语言:javascript
运行
复制
        class UTF8StringCodec : ICustomMarshaler
        {
            public static ICustomMarshaler GetInstance(string cookie) => new UTF8StringCodec();

            public void CleanUpManagedData(object ManagedObj)
            {
                // nop
            }

            public void CleanUpNativeData(IntPtr pNativeData)
            {
                Marshal.FreeCoTaskMem(pNativeData);
            }

            public int GetNativeDataSize()
            {
                throw new NotImplementedException();
            }

            public IntPtr MarshalManagedToNative(object ManagedObj)
            {
                var text = $"{ManagedObj}";
                var bytes = Encoding.UTF8.GetBytes(text);
                var ptr = Marshal.AllocCoTaskMem(bytes.Length + 1);
                Marshal.Copy(bytes, 0, ptr, bytes.Length);
                Marshal.WriteByte(ptr, bytes.Length, 0);
                return ptr;
            }

            public object MarshalNativeToManaged(IntPtr pNativeData)
            {
                if (pNativeData == IntPtr.Zero)
                {
                    return null;
                }

                var bytes = new MemoryStream();
                var ofs = 0;
                while (true)
                {
                    var byt = Marshal.ReadByte(pNativeData, ofs);
                    if (byt == 0)
                    {
                        break;
                    }
                    bytes.WriteByte(byt);
                    ofs++;
                }

                return Encoding.UTF8.GetString(bytes.ToArray());
            }
        }

P/援引声明:

代码语言:javascript
运行
复制
        [DllImport("native.dll", CallingConvention = CallingConvention.Cdecl)]
        private extern static int NativeFunc(
            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8StringCodec))] string path
        );

回调内部的用法:

代码语言:javascript
运行
复制
        [StructLayout(LayoutKind.Sequential)]
        struct Options
        {
            [MarshalAs(UnmanagedType.FunctionPtr)]
            public CallbackFunc callback;
        }

        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate int CallbackFunc(
            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8StringCodec))] string path
        );
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13289171

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档