I found this , but unfortunately there is no Russian ...

Interested in free solutions.

It seems to somehow take advantage of the MS Office API and get results, but the interop is braking.

1 answer 1

Windows 8 - 10

You can use the standard Spell Checking API . Spelling dictionaries are installed with the language pack, so if you have Russian-language Windows, the Russian language will be supported.

Declare the required interfaces:

using System.Runtime.InteropServices; namespace ConsoleApplication1 { public class SpellCheckAPI { public enum WORDLIST_TYPE { WORDLIST_TYPE_IGNORE, WORDLIST_TYPE_ADD, WORDLIST_TYPE_EXCLUDE, WORDLIST_TYPE_AUTOCORRECT, } public enum CORRECTIVE_ACTION { CORRECTIVE_ACTION_NONE, CORRECTIVE_ACTION_GET_SUGGESTIONS, CORRECTIVE_ACTION_REPLACE, CORRECTIVE_ACTION_DELETE, } [Guid("B7C82D61-FBE8-4B47-9B27-6C0D2E0DE0A3")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface ISpellingError { uint StartIndex { get; } uint Length { get; } SpellCheckAPI.CORRECTIVE_ACTION CorrectiveAction { get; } string Replacement { [return: MarshalAs(UnmanagedType.LPWStr)] get; } } [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("803E3BD4-2828-4410-8290-418D1D73C762")] [ComImport] public interface IEnumSpellingError { [return: MarshalAs(UnmanagedType.Interface)] SpellCheckAPI.ISpellingError Next(); } [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("00000101-0000-0000-C000-000000000046")] [ComImport] public interface IEnumString { void Next([In] uint celt, [MarshalAs(UnmanagedType.LPWStr)] out string rgelt, out uint pceltFetched); void Skip([In] uint celt); void Reset(); void Clone([MarshalAs(UnmanagedType.Interface)] out SpellCheckAPI.IEnumString ppenum); } [Guid("432E5F85-35CF-4606-A801-6F70277E1D7A")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface IOptionDescription { string Id { [return: MarshalAs(UnmanagedType.LPWStr)] get; } string Heading { [return: MarshalAs(UnmanagedType.LPWStr)] get; } string Description { [return: MarshalAs(UnmanagedType.LPWStr)] get; } SpellCheckAPI.IEnumString Labels { [return: MarshalAs(UnmanagedType.Interface)] get; } } [Guid("0B83A5B0-792F-4EAB-9799-ACF52C5ED08A")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface ISpellCheckerChangedEventHandler { void Invoke([MarshalAs(UnmanagedType.Interface), In] SpellCheckAPI.ISpellChecker sender); } [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("B6FD0B71-E2BC-4653-8D05-F197E412770B")] [ComImport] public interface ISpellChecker { string languageTag { [return: MarshalAs(UnmanagedType.LPWStr)] get; } [return: MarshalAs(UnmanagedType.Interface)] SpellCheckAPI.IEnumSpellingError Check([MarshalAs(UnmanagedType.LPWStr), In] string text); [return: MarshalAs(UnmanagedType.Interface)] SpellCheckAPI.IEnumString Suggest([MarshalAs(UnmanagedType.LPWStr), In] string word); void Add([MarshalAs(UnmanagedType.LPWStr), In] string word); void Ignore([MarshalAs(UnmanagedType.LPWStr), In] string word); void AutoCorrect([MarshalAs(UnmanagedType.LPWStr), In] string from, [MarshalAs(UnmanagedType.LPWStr), In] string to); byte GetOptionValue([MarshalAs(UnmanagedType.LPWStr), In] string optionId); SpellCheckAPI.IEnumString OptionIds { [return: MarshalAs(UnmanagedType.Interface)] get; } string Id { [return: MarshalAs(UnmanagedType.LPWStr)] get; } string LocalizedName { [return: MarshalAs(UnmanagedType.LPWStr)] get; } uint add_SpellCheckerChanged([MarshalAs(UnmanagedType.Interface), In] SpellCheckAPI.ISpellCheckerChangedEventHandler handler); void remove_SpellCheckerChanged([In] uint eventCookie); [return: MarshalAs(UnmanagedType.Interface)] SpellCheckAPI.IOptionDescription GetOptionDescription([MarshalAs(UnmanagedType.LPWStr), In] string optionId); [return: MarshalAs(UnmanagedType.Interface)] SpellCheckAPI.IEnumSpellingError ComprehensiveCheck([MarshalAs(UnmanagedType.LPWStr), In] string text); } [Guid("8E018A9D-2415-4677-BF08-794EA61F94BB")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface ISpellCheckerFactory { SpellCheckAPI.IEnumString SupportedLanguages { [return: MarshalAs(UnmanagedType.Interface)] get; } int IsSupported([MarshalAs(UnmanagedType.LPWStr), In] string languageTag); [return: MarshalAs(UnmanagedType.Interface)] SpellCheckAPI.ISpellChecker CreateSpellChecker([MarshalAs(UnmanagedType.LPWStr), In] string languageTag); } [Guid("AA176B85-0E12-4844-8E1A-EEF1DA77F586")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface IUserDictionariesRegistrar { void RegisterUserDictionary([MarshalAs(UnmanagedType.LPWStr), In] string dictionaryPath, [MarshalAs(UnmanagedType.LPWStr), In] string languageTag); void UnregisterUserDictionary([MarshalAs(UnmanagedType.LPWStr), In] string dictionaryPath, [MarshalAs(UnmanagedType.LPWStr), In] string languageTag); } [Guid("7AB36653-1796-484B-BDFA-E74F1DB7C1DC")] [ComImport] public class SpellCheckerFactoryClass { } } } 

Then the method for checking spelling can be implemented as follows:

 public static string SpellCheck(string s) { SpellCheckAPI.SpellCheckerFactoryClass factory = null; SpellCheckAPI.ISpellCheckerFactory ifactory = null; SpellCheckAPI.ISpellChecker checker = null; SpellCheckAPI.ISpellingError error = null; SpellCheckAPI.IEnumSpellingError errors = null; SpellCheckAPI.IEnumString suggestions = null; StringBuilder sb = new StringBuilder(s.Length * 10); try { factory = new SpellCheckAPI.SpellCheckerFactoryClass(); ifactory = (SpellCheckAPI.ISpellCheckerFactory)factory; //ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ русского языка int res = ifactory.IsSupported("ru-RU"); if (res == 0) { throw new Exception("Fatal error: russian language not supported!"); } checker = ifactory.CreateSpellChecker("ru-RU"); errors = checker.Check(s); while (true) { if (error != null) { Marshal.ReleaseComObject(error); error = null; } error = errors.Next(); if (error == null) break; //ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ слово с ошибкой string word = s.Substring((int)error.StartIndex, (int)error.Length); sb.AppendLine("Ошибка Π² словС: " + word); //ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌΠΎΠ΅ дСйствиС switch (error.CorrectiveAction) { case SpellCheckAPI.CORRECTIVE_ACTION.CORRECTIVE_ACTION_DELETE: sb.AppendLine("Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌΠΎΠ΅ дСйствиС: ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ"); break; case SpellCheckAPI.CORRECTIVE_ACTION.CORRECTIVE_ACTION_REPLACE: sb.AppendLine("Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌΠΎΠ΅ дСйствиС: Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π½Π° " + error.Replacement); break; case SpellCheckAPI.CORRECTIVE_ACTION.CORRECTIVE_ACTION_GET_SUGGESTIONS: sb.AppendLine("Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌΠΎΠ΅ дСйствиС: Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π½Π° ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… слов"); if (suggestions != null) { Marshal.ReleaseComObject(suggestions); suggestions = null; } //ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ список слов, ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Ρ… для Π·Π°ΠΌΠ΅Π½Ρ‹ suggestions = checker.Suggest(word); sb.Append("[ "); while (true) { string suggestion; uint count = 0; suggestions.Next(1, out suggestion, out count); if (count == 1) sb.Append(suggestion + " "); else break; } sb.Append("] "); sb.AppendLine(); break; } sb.AppendLine(); } } finally { if (suggestions != null) { Marshal.ReleaseComObject(suggestions); } if (factory != null) { Marshal.ReleaseComObject(factory); } if (ifactory != null) { Marshal.ReleaseComObject(ifactory); } if (checker != null) { Marshal.ReleaseComObject(checker); } if (error != null) { Marshal.ReleaseComObject(error); } if (errors != null) { Marshal.ReleaseComObject(errors); } } return sb.ToString(); } 

Windows Vista - 7

You can use TextFox from WPF, tests showed that it works fine in a non-WPF project without the need to create a message loop and add it to the window. You just need to add links to PresentationCore, PresentationFramework, WindowsBase and System.Xaml, as well as mark the stream STAThread. Russian is not supported out of the box, so you will have to download a dictionary, for example, here , and add it as non-standard. It is advisable to transcode the dictionary file to UTF-16 LE with BOM (this encoding is marked as "Unicode" in a notebook), since dictionaries in other encodings seem to be processed incorrectly.

Example:

 using System.Windows.Controls; //... public static string SpellCheckWPF(string s) { StringBuilder sb = new StringBuilder(s.Length * 10); TextBox textbox = new TextBox(); textbox.Text = s; textbox.Language = System.Windows.Markup.XmlLanguage.GetLanguage("en-US"); textbox.SpellCheck.IsEnabled = true; //Π΄ΠΎΠ±Π°Π²ΠΈΠΌ нСстандартный ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ ΠΈΠ· Ρ„Π°ΠΉΠ»Π° textbox.SpellCheck.CustomDictionaries.Add(new Uri(@"ru-RU.dic", UriKind.Relative)); int index = 0; while (true) { //Π½Π°Ρ…ΠΎΠ΄ΠΈΠΌ ΠΎΡˆΠΈΠ±ΠΊΡƒ index = textbox.GetNextSpellingErrorCharacterIndex(index, System.Windows.Documents.LogicalDirection.Forward); if (index > s.Length || index < 0) break; var error = textbox.GetSpellingError(index); int len = textbox.GetSpellingErrorLength(index); string word = textbox.Text.Substring(index, len); sb.AppendFormat("Ошибка Π² словС {0}, рСкомСндуСтся Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π½Π° ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… слов: ", word); //Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌ список ΠΏΡ€Π΅Π΄Π»Π°Π³Π°Π΅ΠΌΡ‹Ρ… Π·Π°ΠΌΠ΅Π½ foreach (string x in error.Suggestions) { sb.Append(x + "; "); } sb.AppendLine(); //ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ ΠΊ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌΡƒ слову index += len; } return sb.ToString(); } 

Since loading a large dictionary takes significant time, you need to create one TextBox, load the dictionary into it once when you start the application and use it in the following code (and not load the dictionary every time you need to check something).

This code will not work in Windows 8.1+ and .NET 4.6.1+, since in these versions WPF also uses the standard API described above. The mechanism for loading dictionaries has changed a lot due to this, and large dictionaries are not supported. In order for everything to work properly in this case, you need to remove the non-standard dictionary and install the Russian language in TextBox, not English.

Sources

Using the C ++ Spell Checking API

WPF in .NET 4.6.1

Spelling checker not supported in the .NET 4.6.1 in some conditions