diff --git a/developer/src/tike/main/KeymanDeveloperOptions.pas b/developer/src/tike/main/KeymanDeveloperOptions.pas index 3e31f27688..a2c1b2af03 100644 --- a/developer/src/tike/main/KeymanDeveloperOptions.pas +++ b/developer/src/tike/main/KeymanDeveloperOptions.pas @@ -82,6 +82,7 @@ type procedure optWriteBool(const nm: string; value: Boolean); procedure optWriteInt(const nm: string; value: Integer); procedure WriteServerConfigurationJson; + class function Get_Initial_DefaultProjectPath: string; static; public procedure Read; procedure Write; @@ -365,7 +366,12 @@ begin FFix183_LadderLength := optReadInt(SRegValue_IDEOpt_WebLadderLength, CRegValue_IDEOpt_WebLadderLength_Default); - FDefaultProjectPath := IncludeTrailingPathDelimiter(optReadString(SRegValue_IDEOpt_DefaultProjectPath, GetFolderPath(CSIDL_PERSONAL) + CDefaultProjectPath)); + FDefaultProjectPath := IncludeTrailingPathDelimiter(optReadString(SRegValue_IDEOpt_DefaultProjectPath, Get_Initial_DefaultProjectPath)); + if (FDefaultProjectPath = '\') or IsRelativePath(FDefaultProjectPath) then + begin + // #11554 + FDefaultProjectPath := Get_Initial_DefaultProjectPath; + end; // for consistency with Keyman.System.KeymanSentryClient, we need to use // reg.ReadInteger, as regReadInt, which in the dim dark past started @@ -613,6 +619,11 @@ begin Result := DefaultEditorThemeItemIndex(s) >= 0; end; +class function TKeymanDeveloperOptions.Get_Initial_DefaultProjectPath: string; +begin + Result := GetFolderPath(CSIDL_PERSONAL) + CDefaultProjectPath; +end; + function LoadKeymanDeveloperSentryFlags: TKeymanSentryClientFlags; begin Result := [kscfCaptureExceptions, kscfShowUI, kscfTerminate]; diff --git a/developer/src/tike/main/UfrmMain.pas b/developer/src/tike/main/UfrmMain.pas index b6468ba222..44b5873245 100644 --- a/developer/src/tike/main/UfrmMain.pas +++ b/developer/src/tike/main/UfrmMain.pas @@ -552,11 +552,22 @@ begin FFilesToOpen := TStringList.Create; - if not ForceDirectories(FKeymanDeveloperOptions.DefaultProjectPath) then - begin - // Fall back to Documents folder if we cannot create the default project path - // Documents folder should always exist - FKeymanDeveloperOptions.DefaultProjectPath := GetFolderPath(CSIDL_PERSONAL); + try + if not ForceDirectories(FKeymanDeveloperOptions.DefaultProjectPath) then + begin + // Fall back to Documents folder if we cannot create the default project path + // Documents folder should always exist + FKeymanDeveloperOptions.DefaultProjectPath := GetFolderPath(CSIDL_PERSONAL); + end; + except + on E:EInOutError do + begin + // If the DefaultProjectPath is a relative, invalid path, then it may + // cause EInOutError (#11554). Note that this exception should no longer + // be possible because the path is sanitized when loaded in + // KeymanDeveloperOptions.pas, but keeping this fallback just in case. + FKeymanDeveloperOptions.DefaultProjectPath := GetFolderPath(CSIDL_PERSONAL); + end; end; FFirstShow := True;