refactor(windows): consolidate Engine install path helper functions

WIP; I need to do more work on this

Test-bot: skip
Build-bot: skip build:windows
This commit is contained in:
Marc Durdin 2025-10-15 09:39:06 +02:00
parent a1c11056d4
commit 165c686cb4
6 changed files with 50 additions and 84 deletions

View file

@ -37,7 +37,8 @@ type
class function KeymanHelpPath(const HelpFile: string): string; static;
class function KeymanUpdateCachePath(const filename: string = ''): string; static;
class function KeymanDesktopInstallPath(const filename: string = ''): string; static;
class function KeymanEngineInstallPath(const filename: string = ''): string; static;
class function KeymanEngineInstallPath(const filename: string = ''; RaiseOnNotFound: Boolean = True): string; static;
class function KeymanEngineExecutablePath(const Executable: string): string; static;
class function KeymanDesktopInstallDir: string; static;
class function KeymanEngineInstallDir: string; static;
class function KeyboardsInstallPath(const filename: string = ''): string; static;
@ -207,7 +208,7 @@ begin
Result := ExtractFileDir(KeymanEngineInstallPath);
end;
class function TKeymanPaths.KeymanEngineInstallPath(const filename: string = ''): string;
class function TKeymanPaths.KeymanEngineInstallPath(const filename: string = ''; RaiseOnNotFound: Boolean): string;
begin
with TRegistry.Create do // I2890
try
@ -221,7 +222,11 @@ begin
Result := GetDebugPath('KeymanEngine', Result);
if Result = '' then
raise EKeymanPath.Create('Unable to find the Keyman Engine directory. You should reinstall the product.');
begin
if RaiseOnNotFound
then raise EKeymanPath.Create('Unable to find the Keyman Engine directory. You should reinstall the product.')
else Exit;
end;
Result := IncludeTrailingPathDelimiter(Result) + filename;
end;
@ -341,7 +346,7 @@ begin
begin
Result := GetFolderPath(CSIDL_COMMON_APPDATA);
if Result = '' then
Result := TKeymanPaths.KeymanEngineInstallPath(TKeymanPaths.S_FallbackKeyboardPath)
Result := TKeymanPaths.KeymanEngineInstallPath(TKeymanPaths.S_FallbackKeyboardPath, False)
else
Result := Result + SFolderKeymanKeyboard;
end;
@ -430,6 +435,30 @@ begin
Result := '';
end;
class function TKeymanPaths.KeymanEngineExecutablePath(const Executable: string): string;
var
keyman_root: string;
begin
// On developer machines, if we are running within the source repo, then use
// those paths
if TKeymanPaths.RunningFromSource(keyman_root) then
begin
// Source repo, bin folder
Result := keyman_root + 'windows\bin\engine\' + Executable;
if FileExists(Result) then Exit;
end;
// For a standard installation, we should find the install path
Result := TKeymanPaths.KeymanEngineInstallPath(Executable, False);
if FileExists(Result) then Exit;
// Fall back to same folder as executable
Result := ExtractFilePath(ParamStr(0)) + Executable;
if FileExists(Result) then Exit;
raise EKeymanPath.Create('Could not find Keyman Engine executable '+Executable);
end;
class function TKeymanPaths.KeymanUpdateCachePath(const filename: string): string;
begin
Result := GetFolderPath(CSIDL_LOCAL_APPDATA) + S_KeymanAppData_UpdateCache + filename;

View file

@ -1962,23 +1962,17 @@ begin
if not IsWow64 then Exit; // I4374
try
// TODO: use TKeymanPaths to find keymanx64?
dir := ExtractFilePath(ParamStr(0));
cmd := dir + 'keymanx64.exe';
cmd := TKeymanPaths.KeymanEngineExecutablePath('keymanx64.exe');
dir := ExtractFileDir(cmd);
params := Format('%d %d', [GetCurrentProcessId, Application.Handle]);
if not FileExists(cmd) then
// We'll get notification of the issue but it won't
// crash the process
raise Exception.Create(cmd+' could not be found');
FillChar(sei, SizeOf(sei), 0);
sei.cbSize := SizeOf(sei);
sei.Wnd := Handle;
sei.lpVerb := 'open';
sei.lpFile := PWideChar(cmd);
sei.lpFile := PChar(cmd);
sei.lpParameters := PChar(params);
sei.lpDirectory := PWideChar(dir);
sei.lpDirectory := PChar(dir);
sei.nShow := SW_SHOW;
if not ShellExecuteExW(@sei) then
@ -1989,6 +1983,8 @@ begin
// We're going to handle any exceptions here but we'd like to know that
// they happened
TKeymanSentryClient.ReportHandledException(E, 'Error starting keymanx64', True);
// TODO: it might be important to tell the user that Keyman is not running
// normally - x64 processes will not receive mapping
end;
end;
end;

View file

@ -688,32 +688,6 @@ end;
procedure TKeymanControl.LoadKeyman32;
function GetKeymanInstallPath: string; // I3598
var
buf: array[0..260] of char;
RootPath: string;
begin
RootPath := '';
with TRegistryErrorControlled.Create do // I2890
try
RootKey := HKEY_LOCAL_MACHINE;
if OpenKeyReadOnly(SRegKey_KeymanEngine_LM) and ValueExists(SRegValue_RootPath) then
RootPath := ReadString(SRegValue_RootPath);
finally
Free;
end;
RootPath := GetDebugPath('Debug_Keyman32Path', RootPath); // I2825
if RootPath = '' then
begin
GetModuleFileName(HInstance, buf, 260);
RootPath := ExtractFilePath(buf);
end;
Result := IncludeTrailingPathDelimiter(RootPath);
end;
function ProcAddr(const Name: string): FARPROC;
begin
Result := GetProcAddress(hlibKeyman32, PChar(Name));
@ -726,7 +700,7 @@ begin
if hlibKeyman32 = 0 then
begin
s := GetKeymanInstallPath+SKeyman32Filename; // I3598
s := TKeymanPaths.KeymanEngineInstallPath(SKeyman32Filename); // I3598
if not FileExists(s) then
ErrorFmt(KMN_E_KeymanControl_CannotLoadKeyman32, VarArrayOf([Integer(GetLastError), 'Failed to find '+SKeyman32Filename+' at "'+s+'", '+SysErrorMessage(GetLastError)]));

View file

@ -322,7 +322,7 @@ begin
prog := Trim(inf.Options.ExecuteProgram);
if prog <> '' then
begin
prog := StringReplace(prog, '$keyman', ExtractFileDir(GetKeymanInstallPath), [rfIgnoreCase, rfReplaceAll]);
prog := StringReplace(prog, '$keyman', TKeymanPaths.KeymanEngineInstallDir, [rfIgnoreCase, rfReplaceAll]);
if not ExecuteProgram(prog, PChar(ExtractFileDir(dest)), errmsg) then
WarnFmt(KMN_W_InstallPackage_CannotRunExternalProgram, VarArrayOf([prog, errmsg]));
end;

View file

@ -1,18 +1,18 @@
(*
Name: utilkeyman
Copyright: Copyright (C) SIL International.
Documentation:
Description:
Documentation:
Description:
Create Date: 20 Jun 2006
Modified Date: 13 Mar 2015
Authors: mcdurdin
Related Files:
Dependencies:
Related Files:
Dependencies:
Bugs:
Todo:
Notes:
Bugs:
Todo:
Notes:
History: 20 Jun 2006 - mcdurdin - Initial version
01 Jun 2009 - mcdurdin - I2001 - use current user not local machine when testing root keyboard path
03 May 2011 - mcdurdin - I2890 - Record diagnostic data when encountering registry errors
@ -54,8 +54,6 @@ function PackageInstalled(const PackageName: string; var FIsAdmin: Boolean): Boo
function GetKeyboardIconFileName(const KeyboardFileName: string): string; // I3599
function GetKeymanInstallPath: string;
function GetDefaultHKL: HKL; // I3581 // I3619 // I3619
var
@ -275,27 +273,6 @@ begin
end;
end;
function GetKeymanInstallPath: string;
var
RootPath: string;
begin
RootPath := ExtractFilePath(ParamStr(0));
with TRegistryErrorControlled.Create do // I2890
try
RootKey := HKEY_LOCAL_MACHINE;
if OpenKeyReadOnly(SRegKey_KeymanEngine_LM) then
if ValueExists(SRegValue_RootPath) then
RootPath := ReadString(SRegValue_RootPath);
finally
Free;
end;
Result := IncludeTrailingPathDelimiter(RootPath);
if not FileExists(Result + 'keyman32.dll') then
raise EKeymanNotInstalled.Create( 'The executable keyman32.dll could not '+
'be found. You should reinstall.');
end;
function GetKeyboardIconFileName(const KeyboardFileName: string): string; // I3599
begin
Result := ChangeFileExt(KeyboardFileName, '.kmx.ico'); // I3581

View file

@ -95,7 +95,7 @@ const
ValueType: kstInteger
);
BaseKeymanSettings: array[0..31] of TKeymanSettingBase = (
BaseKeymanSettings: array[0..30] of TKeymanSettingBase = (
// TIKE:UTikeDebugMode.TikeDebugMode
(
@ -161,16 +161,6 @@ const
DefaultDesc: '%ProgramData%\Keyman\Keyman Engine\Keyboard'
),
// kmcomapi:keymancontrol.TKeymanControl.LoadKeyman32.GetKeymanInstallPath
// keyman32_int.GetKeymanInstallPath
(
ID: 'development.paths.keyman32';
Name: 'Debug_Keyman32Path';
RootKey: HKCU;
Key: SRegKey_KeymanDebug_CU;
Description: 'Path for keyman32.dll; use this when debugging Keyman Core'
),
// KeymanPaths.TKeymanPaths.KeymanEngineInstallPath
(
ID: 'development.paths.keyman_engine_home';
@ -178,7 +168,7 @@ const
RootKey: HKCU;
Key: SRegKey_KeymanDebug_CU;
Description: 'Path for keyman.exe and related resources; use this when '+
'debugging Keyman Configuration';
'debugging Keyman Configuration or Keyman Engine';
DefaultDesc: '%CommonProgramFiles(x86)%\Keyman\Keyman Engine'
),