Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using newer RichEdit versions?

I've tried using RichTextBox on C#, and found it too slow to work with for text thousands of lines of long. After some googling, I found this is because .net by default uses RichEdit 2.0, and a solution is to use RichEdit 5.0 instead.

C# RichEditBox has extremely slow performance (4 minutes loading) SOLVED

It worked fine, with the text displaying in seconds rather than minutes. However, being the kind of person that doesn't care about compatibility in a personal project, I wanted to find later versions of RichEdit. I found out that the latest version is 8.0, the whole of which shipped as riched20.dll, and partially in msftedit.dll.

http://blogs.msdn.com/b/murrays/archive/2006/10/14/richedit-versions.aspx

http://blogs.msdn.com/b/murrays/archive/2012/03/03/richedit-8-0-preview.aspx

However, documentation at msdn stops with 4.1, with (who I assume is) a dev on the project claiming they no longer do public documentation in the blog above.

https://msdn.microsoft.com/en-us/library/windows/desktop/bb787873(v=vs.85).aspx

So far I've been able to run msftedit.dll's RichEdit 2.0 and 5.0 explicitly, but all other versions elude me. For example, despite John Crenshaw's comment claiming RichEdit 6.0 works fine, I have not been able to use it. Any attempt other than the msftedit-2.0 and 5.0 combination mentioned above results in a "Window class name is not valid" error at Application.Run(). (The program is in C#, but I did not tag it as such as I feared this problem might not be a C# specific problem.) The code is a near exact copy of the solution in the first link and is as follows:

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

public static IntPtr LoadLibrary(string s_File)
{
    IntPtr h_Module = LoadLibraryW(s_File);
    if (h_Module != IntPtr.Zero)
        return h_Module;

    int s32_Error = Marshal.GetLastWin32Error();
    throw new Exception("LoadLibrary Failed with: "+s32_Error);
}

protected override CreateParams CreateParams
{
    get
    {
        CreateParams i_Params = base.CreateParams;
        try
        {
            // Available since XP SP1
            LoadLibrary("MsftEdit.dll"); // throws

            i_Params.ClassName = "RichEdit50W";
        }
        catch
        {
            // Windows XP without any Service Pack.
        }
        return i_Params;
    }
}

What I've done is to change the ClassName string to different numbers, e.g. RichEdit60W.

I am on Windows 8.1, so msftedit.dll should have up to RichEdit 7.0 or 8.0 (the wording given in the blog post is unclear), yet I am unable to reach them. Is there any way to correct this, or are the newer versions confidencial?

like image 300
dare0021 Avatar asked Apr 06 '15 15:04

dare0021


2 Answers

I have RichEdit version 8.0 on my machine, class name RICHEDIT60W. It is stored in C:\Program Files (x86)\Common Files\Microsoft Shared\OFFICE15\RICHED20.DLL. It works just fine when I write a wrapper for it:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.ComponentModel;

class RichEdit80 : RichTextBox {
    protected override CreateParams CreateParams {
        get {
            if (moduleHandle == IntPtr.Zero) {
                string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFilesX86);
                path = System.IO.Path.Combine(path, @"Microsoft Shared\OFFICE15\RICHED20.DLL");
                moduleHandle = LoadLibrary(path);
                if ((long)moduleHandle < 0x20) throw new Win32Exception(Marshal.GetLastWin32Error(), "RichEdit control appears to be missing");
            }
            CreateParams createParams = base.CreateParams;
            createParams.ClassName = "RichEdit60W";
            if (this.Multiline) {
                if (((this.ScrollBars & RichTextBoxScrollBars.Horizontal) != RichTextBoxScrollBars.None) && !base.WordWrap) {
                    createParams.Style |= 0x100000;
                    if ((this.ScrollBars & ((RichTextBoxScrollBars)0x10)) != RichTextBoxScrollBars.None) {
                        createParams.Style |= 0x2000;
                    }
                }
                if ((this.ScrollBars & RichTextBoxScrollBars.Vertical) != RichTextBoxScrollBars.None) {
                    createParams.Style |= 0x200000;
                    if ((this.ScrollBars & ((RichTextBoxScrollBars)0x10)) != RichTextBoxScrollBars.None) {
                        createParams.Style |= 0x2000;
                    }
                }
            }
            if ((BorderStyle.FixedSingle == base.BorderStyle) && ((createParams.Style & 0x800000) != 0)) {
                createParams.Style &= -8388609;
                createParams.ExStyle |= 0x200;
            }
            return createParams;
        }
    }

    private static IntPtr moduleHandle;

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr LoadLibrary(string lpFileName);
}

Not thoroughly tested. Hopefully you are very uncomfortable with this code, it is really only good enough for testing purposes to see if you are ahead at all. The path of the DLL is of course the Big Red flag, you'll have to change it when you don't have Office 2013 on your machine. Demanding that the user has the correct Office version installed on his machine only works well when you have decent control over the machines on which your program is going to run. Using a fall-back path when LoadLibrary() fails is technically possible.

What this specific version does and how it might be incompatible with the default RichTextBox in the toolbox is pretty hard to reverse-engineer. The rough guess is "more compatible with Word". Later RichEdit versions better support math equations for example. Only way you can find out is by thoroughly testing. Best to stick with msftedit.dll

like image 132
Hans Passant Avatar answered Oct 10 '22 14:10

Hans Passant


RichEdit seems to be primarily developed at Microsoft as part of Office, with only versions 1.0, 2.0, 3.0 and 4.1 being included in Windows at various times.

Other, later versions of RichEdit can be found inside Microsoft Office installations: you would have to LoadLibrary() them explicitly from their location under "Program Files" if Office is installed. If Office isn't installed you are out of luck: these other versions are not present in bare Windows, and there's no redistribution licence to allow you to distribute them with any appropriate you write.

So, basically, you're out of luck. Sorry.

like image 3
DavidK Avatar answered Oct 10 '22 15:10

DavidK