1

We use external component (MigraDoc) to compose an RTF document. Which then is converted to plain text by assigning RTF as string to System.Windows.Forms.RichTextBox's Rtf field and reading Text field. This has worked earlier but now we have found a problem (which has been there for a while already).

Plain text conversion is not working on Windows 10 but same application is working on Windows 7. After assigning Rft field, the Text field remains empty and also Rft field doesn't have the value which was just assigned. *

However, earlier version of our application is working on Windows 10 as well. Even there are no direct constitutive changes on this area. One possibly affecting change is .Net target version change from 4.0 to 4.7.2 (but it is hard to verify this anymore).

If I take the RTF string from Windows 7 and save it as file, it opens on WordPad on Windows 7. But it doesn't open on WordPad on Windows 10.

Have somebody else phased similar issues? Or are there any ideas how this could be fixed?



* But instead value:

{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}
{\*\generator Riched20 10.0.19041}\viewkind4\uc1 
\pard\f0\fs17\par
}



EDIT: MigraDoc version is 1.32 i.e. the latest non-beta.

joof
  • 23
  • 7
  • Are you on the latest version of MigraDoc? – Charlieface Jan 27 '23 at 09:45
  • 1
    Your app's previous version was probably loading `RICHEDIT20W`, while targeting .NET Framework 4.7.2+, you're using `RICHEDIT50W`. You can build a Custom Control that loads the `riched20.dll` library, found in System32, then set the `[CreateParams].ClassName` of the Control to `RICHEDIT20W` in the `CreateParams` override. See whether using the old Control changes something for you. Anyway, check with Inspect.exe or Spy++ what versions of the RichEdit / MsftEdit Controls are in use in the different versions of your app – Jimi Jan 27 '23 at 11:46
  • On Windows 10, the current app version loads `msftedit.dll` but the earlier app version loads `riched20.dll`. So this must be the key. (And msftedit versions are different on W7 (v4.1) and on W10 (v8.5) which could explain different behavior between them.) @Jimi Thank you very much! Next I try to make a custom control. – joof Jan 27 '23 at 14:03
  • As long as the code targets the .Net Framework (not .Net/Core), you can use the `AppContextSwitchOverrides` section in the `App.Config` to downgrade to the older RichEdit control by specifying the Switch.System.Windows.Forms.DoNotLoadLatestRichEditControl override. [See this post](https://stackoverflow.com/a/56938772/2592875) for a usage example. – TnTinMn Jan 27 '23 at 14:35

1 Answers1

1

If you want to try out the RICHEDIT20W version of RichEdit Control (Rich Text Edit Control v. 3.1), use a Custom Control built like this one. It tries to load the riched20.dll library and, if it succeeds, it then sets the Class name of the Control in the CreateParams override.

You could also try to load the RICHEDIT60W version that is usually shipped with MS Office installations, for testing. This version has also different behavior.
In this case, you have to provide the full path of the library, which depends on the installed Office version and bitness

In practice, you have means to use a specific version of the Control.
Tweak this code to make it act as you prefer. As it is, it allows to switch between ver. RICHEDIT20W and RICHEDIT50W (design-time or run-time)

using System.ComponentModel;
using System.Runtime.InteropServices;

public class RichTextBox20W : RichTextBox {
    private bool m_UseRichedit20 = true;

    public RichTextBox20W() {
         IsRichEdit20Available = LoadLibrary("riched20.dll") != IntPtr.Zero;
    }

    [DefaultValue(true)]
    public bool UseRichedit20 { 
        get => m_UseRichedit20 & IsRichEdit20Available;
        set {
            if (value != m_UseRichedit20) {
                m_UseRichedit20 = value;
                RecreateHandle();
            }
        } 
    }

    public bool IsRichEdit20Available { get; }

    protected override CreateParams CreateParams {
        get {
            var cp = base.CreateParams;
            if (UseRichedit20) {
                cp.ClassName = "RICHEDIT20W";
            }
            // If the library is not found, the class name is set to RICHEDIT50W 
            // which is the default when targeting .NET Framework 4.7.2+
            return cp;
        }
    }

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern IntPtr LoadLibrary(string lpLibFileName);
}
Jimi
  • 29,621
  • 8
  • 43
  • 61