在Windows 10 1803上的RichTextBox中没有下划线的超链接

Mar*_*ryl 11 .net c# winapi rtf richtextbox

我正在显示RTF文档RichTextBox("已升级" RichEdit50W).文档中的关键字使用语法链接到网页:

{\field{\*\fldinst{HYPERLINK ""https://www.example.com/"" }}{\fldrslt{\cf1 keyword\cf0 }}}
Run Code Online (Sandbox Code Playgroud)

我不想强调关键字.在Windows 10版本1803(以及所有以前版本的Windows,包括XP,Vista,8)中,只要在锚点上设置了颜色(注意\cf1),锚点就不会加下划线.

但这不再适用于Windows 10版本1803.我将向Microsoft报告此情况.但我不确定,如果我不依赖于无证件的行为.我可以想象这个改变实际上不是一个错误,而是一个修复.所以我想知道是否有更正确的方法来防止超链接加下划线.

示例代码:

public class ExRichText : RichTextBox
{
    [DllImport("kernel32.dll", EntryPoint = "LoadLibraryW", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern IntPtr LoadLibraryW(string path);

    protected override CreateParams CreateParams
    {
        get
        {
            var cp = base.CreateParams;
            LoadLibraryW("MsftEdit.dll");
            cp.ClassName = "RichEdit50W";
            return cp;
        }
    }
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        ExRichText rtb = new ExRichText();
        rtb.Parent = this;
        rtb.SetBounds(10, 10, 200, 100);
        rtb.Rtf = @"{\rtf1 {\colortbl ;\red255\green0\blue0;}bar {\field{\*\fldinst{HYPERLINK ""https://www.example.com/"" }}{\fldrslt{\cf1 link\cf0 }}} bar}";
    }
}
Run Code Online (Sandbox Code Playgroud)

Windows 10版本1803上的(不需要的)结果:

在此输入图像描述

Windows 10版本1706上的(所需)结果:

在此输入图像描述

和Windows 7上相同的结果:

在此输入图像描述

TnT*_*nMn 6

对于Windows 8及更高版本,您可以使用SendMessage函数EM_SETEDITSTYLEEX消息发送到richedit控件,以通过为lParam参数指定SES_EX_HANDLEFRIENDLYURL 并为wParam`参数指定零来禁用友好链接的下划线。

SES_EX_HANDLEFRIENDLYURL

如果不使用临时格式或使用文本自动上色(默认值:0),则以友好的名称显示具有与自动链接相同的文本颜色和下划线的友好名称链接。

即使默认情况下未指定下划线,RichTextBox控件也已启用它。

将以下内容添加到您的ExRichText类中以提供一种方法(UnderlineFriendlyLink)以禁用下划线。

private const Int32 WM_User = 0x400;
private const Int32 EM_SETEDITSTYLEEX = WM_User + 275;
private const Int32 EM_GETEDITSTYLEEX = WM_User + 276;

/// <summary>Display friendly name links with the same text color and underlining as automatic links, provided that temporary formatting isn’t used or uses text autocolor (default: 0)</summary>
private const Int32 SES_EX_HANDLEFRIENDLYURL = 0x100;

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private extern static Int32 SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, Int32 lParam);

public static void UnderlineFriendlyLink(RichTextBox rtb, bool enabled = false)
{
    if (rtb.IsHandleCreated)
    {
        Int32 wParam = enabled ? SES_EX_HANDLEFRIENDLYURL : 0;
        Int32 lParam = SES_EX_HANDLEFRIENDLYURL; // settings mask
        Int32 res = SendMessage(new HandleRef(null, rtb.Handle), EM_SETEDITSTYLEEX, wParam, lParam);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        exRichText1.Rtf = @"{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}{\colortbl ;\red0\green0\blue255;}{\*\generator Riched20 10.0.16299}\viewkind4\uc1 \pard\f0\fs29 Hello {\b{\field{\*\fldinst{HYPERLINK ""http://www.fred.com""}}{\fldrslt{Link}}}}\f0\fs29\par\par https://www.google.com \par\par sd {{\field{\*\fldinst{HYPERLINK ""http://www.fred.com""}}{\fldrslt{klasl}}}}\f0\fs29  wed asdasd \par\par}";
    }

    private void exRichText1_LinkClicked(object sender, LinkClickedEventArgs e)
    {
        System.Diagnostics.Debug.Print(e.LinkText);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        ExRichText.UnderlineFriendlyLink(exRichText1, false);
    }
}
Run Code Online (Sandbox Code Playgroud)

您的帖子并未指出您如何检测链接的单击,但是请注意,如果您依赖LinkClicked上述示例中所示的事件,则由于RichTextBox CharRangeToString方法中的逻辑错误,该事件可能不会触发。特别是此代码片段。

        //Windows bug: 64-bit windows returns a bad range for us.  VSWhidbey 504502.  
        //Putting in a hack to avoid an unhandled exception.
        if (c.cpMax > Text.Length || c.cpMax-c.cpMin <= 0) {
            return string.Empty;
        }
Run Code Online (Sandbox Code Playgroud)

如果您尝试示例代码,您将注意到该事件仅针对第一个链接触发。如果CharRangeToString返回String.Empty,则不会引发该事件。该限制条件使用Text.Length返回显示长度的属性(示例为58)。我相信它应该改为使用TextLength属性(示例为120)。

通过监视控件的父控件的EM_Notify消息并处理鼠标单击通知,可以在为x86或AnyCPU(首选32位)进行编译时使用CharRange结构提取链接。当以64位程序集运行时,CharRange结构的确会返回无效值,如源代码中所示。


编辑:所有测试都在Windows 10版本1706上完成,因为我现在不会安装1803。