Dan*_*n W 10 c# rtf utf-8 richtextbox winforms
我想我已经在Windows或.NET中发现了一个错误,正在寻找解决方法。
要重现该问题,请首先启用Windows功能“ Beta:使用Unicode UTF-8进行全球语言支持”。
您可能需要重启机器。
现在,只需在Winforms / C#中创建两个RichTextBox组件,然后添加事件:
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
string s = richTextBox1.Rtf;
richTextBox2.Rtf = s;
}
Run Code Online (Sandbox Code Playgroud)
最后,运行该程序,只需在第一个RichTextBox中键入一些内容,当它尝试写入时就会崩溃,并显示消息“文件格式无效” richTextBox2.Rtf。如果Windows功能“测试版:将Unicode UTF-8用于全球语言支持”被禁用,则不会崩溃。
我在这里考虑两个潜在的解决方法:
1:以某种方式在C#应用程序中禁用了整个“测试版:使用Unicode UTF-8进行全球语言支持”功能,并假装从未启用过该功能。
2:在调整另一个RichTextBox的RTF之前,以某种方式编辑RTF字符串以符合新RTF应该具有的未知要求。考虑到第一个RichTextBox应该具有完全相同的RTF,这似乎是违反直觉的,但是无论如何...
************* Exception Text **************
System.ArgumentException: File format is not valid.
at System.Windows.Forms.RichTextBox.StreamIn(Stream data, Int32 flags)
at System.Windows.Forms.RichTextBox.StreamIn(String str, Int32 flags)
at System.Windows.Forms.RichTextBox.set_Rtf(String value)
at unicodeTesting.Form1.richTextBox1_TextChanged(Object sender, EventArgs e) in D:\Code\c#\_tests\unicodeTesting\Form1.cs:line 30
at System.Windows.Forms.Control.OnTextChanged(EventArgs e)
at System.Windows.Forms.TextBoxBase.OnTextChanged(EventArgs e)
at System.Windows.Forms.TextBoxBase.WmReflectCommand(Message& m)
at System.Windows.Forms.TextBoxBase.WndProc(Message& m)
at System.Windows.Forms.RichTextBox.WmReflectCommand(Message& m)
at System.Windows.Forms.RichTextBox.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
Run Code Online (Sandbox Code Playgroud)
Microsoft开源了WinForms库,因此您可以自己深入研究源代码:
https://github.com/dotnet/winforms/tree/master/src/System.Windows.Forms/src/System/Windows/Forms
StreamIn方法位于https://github.com/dotnet/winforms/blob/master/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBox.cs的第3140行:
private void StreamIn(string str, int flags)
{
if (str.Length == 0)
{
// Destroy the selection if callers was setting
// selection text
//
if ((RichTextBoxConstants.SFF_SELECTION & flags) != 0)
{
SendMessage(Interop.WindowMessages.WM_CLEAR, 0, 0);
ProtectedError = false;
return;
}
// WM_SETTEXT is allowed even if we have protected text
//
SendMessage(Interop.WindowMessages.WM_SETTEXT, 0, "");
return;
}
// Rather than work only some of the time with null characters,
// we're going to be consistent and never work with them.
int nullTerminatedLength = str.IndexOf((char)0);
if (nullTerminatedLength != -1)
{
str = str.Substring(0, nullTerminatedLength);
}
// get the string into a byte array
byte[] encodedBytes;
if ((flags & RichTextBoxConstants.SF_UNICODE) != 0)
{
encodedBytes = Encoding.Unicode.GetBytes(str);
}
else
{
encodedBytes = Encoding.Default.GetBytes(str);
}
editStream = new MemoryStream(encodedBytes.Length);
editStream.Write(encodedBytes, 0, encodedBytes.Length);
editStream.Position = 0;
StreamIn(editStream, flags);
}
private void StreamIn(Stream data, int flags)
{
// clear out the selection only if we are replacing all the text
//
if ((flags & RichTextBoxConstants.SFF_SELECTION) == 0)
{
NativeMethods.CHARRANGE cr = new NativeMethods.CHARRANGE();
UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), Interop.EditMessages.EM_EXSETSEL, 0, cr);
}
try
{
editStream = data;
Debug.Assert(data != null, "StreamIn passed a null stream");
// If SF_RTF is requested then check for the RTF tag at the start
// of the file. We don't load if the tag is not there
//
if ((flags & RichTextBoxConstants.SF_RTF) != 0)
{
long streamStart = editStream.Position;
byte[] bytes = new byte[SZ_RTF_TAG.Length];
editStream.Read(bytes, (int)streamStart, SZ_RTF_TAG.Length);
string str = Encoding.Default.GetString(bytes);
if (!SZ_RTF_TAG.Equals(str))
{
throw new ArgumentException(SR.InvalidFileFormat);
}
// put us back at the start of the file
editStream.Position = streamStart;
}
int cookieVal = 0;
// set up structure to do stream operation
NativeMethods.EDITSTREAM es = new NativeMethods.EDITSTREAM();
if ((flags & RichTextBoxConstants.SF_UNICODE) != 0)
{
cookieVal = INPUT | UNICODE;
}
else
{
cookieVal = INPUT | ANSI;
}
if ((flags & RichTextBoxConstants.SF_RTF) != 0)
{
cookieVal |= RTF;
}
else
{
cookieVal |= TEXTLF;
}
es.dwCookie = (IntPtr)cookieVal;
es.pfnCallback = new NativeMethods.EditStreamCallback(EditStreamProc);
// gives us TextBox compatible behavior, programatic text change shouldn't
// be limited...
//
SendMessage(Interop.EditMessages.EM_EXLIMITTEXT, 0, int.MaxValue);
// go get the text for the control
// Needed for 64-bit
if (IntPtr.Size == 8)
{
NativeMethods.EDITSTREAM64 es64 = ConvertToEDITSTREAM64(es);
UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), Interop.EditMessages.EM_STREAMIN, flags, es64);
//Assign back dwError value
es.dwError = GetErrorValue64(es64);
}
else
{
UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), Interop.EditMessages.EM_STREAMIN, flags, es);
}
UpdateMaxLength();
// If we failed to load because of protected
// text then return protect event was fired so no
// exception is required for the the error
if (GetProtectedError())
{
return;
}
if (es.dwError != 0)
{
throw new InvalidOperationException(SR.LoadTextError);
}
// set the modify tag on the control
SendMessage(Interop.EditMessages.EM_SETMODIFY, -1, 0);
// EM_GETLINECOUNT will cause the RichTextBoxConstants to recalculate its line indexes
SendMessage(Interop.EditMessages.EM_GETLINECOUNT, 0, 0);
}
finally
{
// release any storage space held.
editStream = null;
}
}
Run Code Online (Sandbox Code Playgroud)
它看起来确实像是个错误,并且由于它是测试版,因此最好的做法是将其记录在Microsoft的https://developercommunity.visualstudio.com上。
如果用库中的代码替换RichTextBox控件类,则可以在以下位置查看发生错误的行:
System.Windows.Forms.RichTextBox.StreamIn(Stream data, Int32 flags)
更新:
已经向Microsooft报告过:https : //developercommunity.visualstudio.com/content/problem/544623/issue-caused-by-unicode-utf-8-for-world-wide-langu.html
MSFT的Kyle Wang已将其范围缩小到一个操作系统问题:
PC1(OS Build .437可以重现该问题):
信封:
PC2(操作系统内部版本.348无法重现该问题):
信封:
测试:
| 归档时间: |
|
| 查看次数: |
457 次 |
| 最近记录: |