fix(windows): crash when installing TIP in some rare situations

May fix #4889.

In some situations, Keyman is unable to precisely match the user's
default language with its own keyboard settings. In this situation,
Keyman may crash when attempting to install the TIP, or may give a
spurious error such as "Too many transient languages" or similar.

I have been unable to reproduce the crash described in #4889 on my
machines so this is an attempted fix.

This does fix a bug with default languages in any case so is a good fix
to include: if the user's default language is not found in Keyman's LCID
table, then Keyman would fail to install the TIP when the keyboard is
installed and would return an error message (but not crash).
This commit is contained in:
Marc Durdin 2021-04-19 10:39:49 +10:00
parent c225d65a71
commit e86704b702
2 changed files with 56 additions and 2 deletions

View file

@ -43,6 +43,7 @@ implementation
uses
System.SysUtils,
System.Win.Registry,
Winapi.Windows,
Keyman.System.LanguageCodeUtils,
@ -50,8 +51,10 @@ uses
BCP47Tag,
glossary,
kmint,
RegistryKeys,
utilkmshell,
utilexecute;
utilexecute,
utilsystem;
{ TTIPMaintenance }
@ -199,8 +202,58 @@ begin
end;
class function TTIPMaintenance.GetUserDefaultLanguage: string;
var
r: TRegistry;
tags: TStringList;
v: string;
keys: TStringList;
key: string;
begin
Result := TLanguageCodeUtils.TranslateWindowsLanguagesToBCP47(HKLToLanguageID(GetDefaultHKL))
// Fallback result
Result := TLanguageCodeUtils.TranslateWindowsLanguagesToBCP47(HKLToLanguageID(GetDefaultHKL));
// For Win10, look in CPL/International/UserProfile
r := TRegistry.Create;
try
if not r.OpenKeyReadOnly(SRegKey_ControlPanelInternationalUserProfile) then
Exit;
if r.ValueExists(SRegValue_CPIUP_InputMethodOverride) then
begin
// Lookup the override input method BCP 47 tag
v := r.ReadString(SRegValue_CPIUP_InputMethodOverride);
keys := TStringList.Create;
try
r.GetKeyNames(keys);
for key in keys do
begin
if r.OpenKeyReadOnly('\' + SRegKey_ControlPanelInternationalUserProfile + '\' + key) and
r.ValueExists(v) then
begin
Result := key;
Break;
end;
end;
finally
keys.Free;
end;
end
else if r.ValueExists(SRegValue_CPIUP_Languages) then
begin
// The first tag is the default language tag
tags := TStringList.Create;
try
r.ReadMultiString(SRegValue_CPIUP_Languages, tags);
if tags.Count > 0 then
begin
Result := tags[0].Trim;
end;
finally
tags.Free;
end;
end;
finally
r.Free;
end;
end;
class function TTIPMaintenance.GetFirstLanguage(Keyboard: IKeymanKeyboardFile): string;

View file

@ -270,6 +270,7 @@ const
SRegValue_CPIUP_Languages = 'Languages';
SRegValue_CPIUP_TransientLangId = 'TransientLangId';
SRegValue_CPIUP_CachedLanguageName = 'CachedLanguageName';
SRegValue_CPIUP_InputMethodOverride = 'InputMethodOverride';
{ User profile keys }