user3819222
user3819222

Reputation: 127

C# helpProvider SetHelpString does not support unicode

I am using HelpProvider to show help for my control.

I input the help string for HelpProvider control. But this does not show the string properly.

P/S:

My language is Vietnam, which is a unicode font.

Here is my text when progamming: "Chúc mừng năm mới"

Here is the text when shown:

enter image description here

Upvotes: 3

Views: 261

Answers (1)

Reza Aghaei
Reza Aghaei

Reputation: 125217

It's an old bug and it's because of two problems:

  • The default font which is used by underlying API of the HelpProvider doesn't support unicode characters
  • The underlying API of the HelpProvider doesn't support Unicode.

After fixing these two problems, you can show Unicode characters correctly:

HelpExtensions.ShowPopup2(button1, "متن آزمایشی", Control.MousePosition);

enter image description here

The first problem is in Help class(.NET 4.X, .NET 5) which has created the HH_POPUP but hasn't specified any font for it. As a result a default font which doesn't support Unicode characters will be used.

  • A possible fix is using a default font like SystemFonts.CaptionFont which supports Unicode characters.

For the second problem, you need to change a setting in Windows, to do so:

  • Go to Control Panel → Region → Administrative tab, then in the section "Language for non-Unicode programs", click on "Change system locale ..." button and then in the next dialog, choose the language of your choice, for example Persian.

    Or to support other languages as well you can choose: "Beta: Use Unicode UTF-8 for worldwide language support" which is Beta.

enter image description here

And here is HelpExtensions class:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public static class HelpExtensions
{
    public static void ShowPopup2(Control parent, string caption, Point location, Font font = null, Color? backColor = null, Color? foreColor = null)
    {
        font = font ?? SystemFonts.CaptionFont;
        backColor = backColor ?? Color.FromKnownColor(KnownColor.Window);
        foreColor = foreColor ?? Color.FromKnownColor(KnownColor.WindowText);

        var popup = new HH_POPUP();
        popup.clrBackground = new COLORREF(backColor.Value);
        popup.clrForeground = new COLORREF(foreColor.Value);
        popup.pt = new POINT(location);
        var pszText = Marshal.StringToCoTaskMemAuto(caption);
        popup.pszText = pszText;
        var pszFont = Marshal.StringToCoTaskMemAuto(
            $"{font.Name}, {font.Size}, , " +
            $"{(font.Bold ? "BOLD" : "")}" +
            $"{(font.Italic ? "ITALIC" : "")}" +
            $"{(font.Underline ? "UNDERLINE" : "")}");
        popup.pszFont = pszFont;
        try
        {
            HtmlHelp(parent.Handle, null, HTMLHelpCommand.HH_DISPLAY_TEXT_POPUP, popup);
        }
        finally
        {
            Marshal.FreeCoTaskMem(pszText);
            Marshal.FreeCoTaskMem(pszFont);
        }
    }

    [Flags()]
    public enum HTMLHelpCommand : uint
    {
        HH_DISPLAY_TOPIC = 0,
        HH_DISPLAY_TOC = 1,
        HH_DISPLAY_INDEX = 2,
        HH_DISPLAY_SEARCH = 3,
        HH_DISPLAY_TEXT_POPUP = 0x000E,
        HH_HELP_CONTEXT = 0x000F,
        HH_CLOSE_ALL = 0x0012
    }

    [DllImport("hhctrl.ocx", SetLastError = true, EntryPoint = "HtmlHelpW", CharSet = CharSet.Unicode)]
    static extern int HtmlHelp(IntPtr hWndCaller,
        [MarshalAs(UnmanagedType.LPWStr)] string pszFile,
        HTMLHelpCommand uCommand,
        [MarshalAs(UnmanagedType.LPStruct)] HH_POPUP dwData);

    [StructLayout(LayoutKind.Sequential)]
    struct COLORREF
    {
        int ColorRef;

        public COLORREF(int lRGB)
        {
            ColorRef = lRGB & 0x00ffffff;
        }
        public COLORREF(Color color) : this(color.ToArgb())
        {
        }
    }
    [StructLayout(LayoutKind.Sequential)]
    class POINT
    {
        public int x;
        public int y;
        public POINT(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        public POINT(Point p) : this(p.X, p.Y)
        {
        }
    }
    [StructLayout(LayoutKind.Sequential)]
    struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
        public RECT(int left, int top, int right, int bottom)
        {
            this.left = left;
            this.top = top;
            this.right = right;
            this.bottom = bottom;
        }
        public RECT(Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom)
        {
        }
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    class HH_POPUP
    {
        internal int cbStruct = Marshal.SizeOf(typeof(HH_POPUP));
        internal IntPtr hinst = IntPtr.Zero;
        internal int idString = 0;
        internal IntPtr pszText;
        internal POINT pt;
        internal COLORREF clrForeground = new COLORREF(-1);
        internal COLORREF clrBackground = new COLORREF(-1);
        internal RECT rcMargins = new RECT(-1, -1, -1, -1);
        internal IntPtr pszFont;
    }
}

HelpProvider2 Component

I've created a HelpProvider2 component which supports Unicode characters. It also exposes Font, ForeColor and BackColor properties:

HelpProvider2Properties.png

Download or clone

Upvotes: 3

Related Questions