Microsoft released a Windows Update this week that caused quite a problem for Delphi developers still using Delphi 2006 to 2010. When starting a second instance of the IDE they now get the error
Cannot create file C:\Users\Admin\AppData\Local\Temp\EditorLineEnds.ttr
The update in question is a security update for all supported Windows versions and has the number KB2982791. It prevents the file EditorLineEnds.ttr to be created/overwritten because that file is a Truetype font and changing it while it is active is apparently a security risk.
Unfortunately this prevents a meaningful use of these Delphi versions. So what can we do?
There is this question on StackOverflow from which I got the above information. As far as I know there are the following workarounds:
Uninstall the Windows update KB2982791, which might not be such a good idea. After all it’s a security update. Daniel Magin blogged about this.
Use Andreas Hausladen’s IdeFixpack (Delphi 2007 version, beware that version 4.4 does not work under Windows 8, version 4.3 seems to work), (for later Delphi versions). Note that the editor option Show Lineends will use a different character if you use this fix because the IDE won’t load the EditorLineEnds.ttr font any more.
Rename the file every time you want to start Delphi. This is what I will be writing more about.
Of course you don’t want to rename the file by hand every time you start Delphi. So either, you use a batch file to do that for you (see Daniel Magin’s post), or you use the program I wrote for this particular task.
It’s called dzEditorLineEndsFix and is a Tray Icon application that uses FindFirstChangeNotification / FindNextChangeNotification (I always wanted to use these API functions but never had an appropriate use case.) to detect when the file is being created and then moves it to its own unique subdirectory under %temp%.
In theory it will clean up after itself, but that might fail because the file(s) are still in use. So once in a while you should have a look into your %temp% folder and delete all subdirectories called ttr* from it.
Moje primedbe:
- Nema potrebe da stalno radi u Trayu
- Nema potrebe da se povremeno proverava temp folder i brise
Kod koji saljem je za Delphi starter koji ce promeniti "temp" enviroment promenljivu koju ce koristiti Delphi kada bude startovan. To radi tako sto Delphi preuzima od startera sve enviroment promenljive pa i izmenjenu "temp". Svaka nova instanca Delphija ce imati svoj temp folder.
Temp folderi se brisu pri svakom startovanju, ako mogu da se obrisu. Ne moze da se brise onda kada se koristi, sto znaci da ce biti obrisano sve kada se restartuje racunar i pokrene starter.
Ako neko ne gasi racunar onda nece moci da mu bude rasciscen temp brojac i temp dir sve dok ne restartuje racunar.
Code (delphi):
program DelphiEditorLineEndsTtrRun;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils, ShellApi, IniFiles;
procedure SetTempTmpPath(tempPath, TempSubFolder: string);
var
instName: string;
i: Integer;
function EraseFolder(AFolderName: string; ARemoveFolder: Boolean = True): string;
var
SRec: TSearchRec;
FolderName: string;
begin
Result := '';
if AFolderName = '' then
Exit;
FolderName := IncludeTrailingPathDelimiter(AFolderName);
if FindFirst(FolderName + '*.*', faAnyFile or faDirectory, SRec) = 0 then
begin
repeat
if (SRec.Name <> '.')and(SRec.Name <> '..') then
if SRec.Attr and faDirectory = faDirectory then
Result := EraseFolder(FolderName + SRec.Name, True)
else
if not DeleteFile(FolderName + SRec.Name) then
begin
Writeln('Cannot DeleteFile: ' + FolderName + SRec.Name);
Result := SRec.Name;
end;
if length(Result) > 0 then
exit;
until FindNext(SRec) <> 0;
FindClose(SRec);
end;
if ARemoveFolder then
begin
FolderName := ExcludeTrailingPathDelimiter(FolderName);
if not RemoveDir(FolderName) then
begin
Writeln('Cannot RemoveDir: ' + FolderName);
Result := FolderName;
end;
end;
end;
begin
tempPath := IncludeTrailingPathDelimiter(TempPath) + TempSubFolder;
if not DirectoryExists(tempPath) then
ForceDirectories(tempPath);
if DirectoryExists(tempPath) then
begin
tempPath := IncludeTrailingPathDelimiter(tempPath);
i := 1;
while i < 100 do
begin
instName := 'Inst'+IntToStr(i);
if DirectoryExists(tempPath + instName) then
EraseFolder(tempPath + instName);
Inc(i);
end;
i := 1;
while i < 100 do
begin
instName := 'Inst'+IntToStr(i);
if not DirectoryExists(tempPath + instName) then
break;
Inc(i);
end;
if not DirectoryExists(tempPath + instName) then
begin
ForceDirectories(tempPath + instName);
if DirectoryExists(tempPath + instName) then
begin
Windows.SetEnvironmentVariable('TEMP', PChar(tempPath + instName));
Windows.SetEnvironmentVariable('TMP', PChar(tempPath + instName));
end else
raise Exception.Create('Cannot create: ' + tempPath + instName);
end else
raise Exception.Create('Exists: ' + tempPath + instName);
end else
raise Exception.Create('Not exists: ' + tempPath);
end;
var
TempPath: string;
iniFile: TIniFile;
TempDelphiSubFolder: string;
PathToBDS: PChar;
Parameters: PChar;
pCount: Integer;
begin
try
pCount := ParamCount;
if pCount < 1 then
raise Exception.Create('Need EditorLineEndsTtr.ini section as parameter ');
iniFile := TIniFile.Create(ExtractFilePath(ExcludeTrailingPathDelimiter(ParamStr(0))) + 'EditorLineEndsTtr.ini');
try
TempDelphiSubFolder := iniFile.ReadString(ParamStr(1), 'TempDelphiSubFolder', 'Delphi 2010');
PathToBDS := PChar(iniFile.ReadString(ParamStr(1), 'PathToDelphi', 'C:\Program Files (x86)\Embarcadero\RAD Studio\7.0\bin\bds.exe'));
Parameters := PChar(iniFile.ReadString(ParamStr(1), 'Parameters', '-pDelphi'));
finally
iniFile.Free;
end;
SetLength(TempPath, MAX_PATH);
Windows.GetEnvironmentVariable('TEMP', PChar(TempPath), MAX_PATH);
TempPath := PChar(TempPath);
Writeln('TEMP: ' + TempPath);
Windows.GetEnvironmentVariable('TMP', PChar(TempPath), MAX_PATH);
TempPath := PChar(TempPath);
Writeln('TMP: ' + TempPath);
SetTempTmpPath(TempPath, TempDelphiSubFolder);
Windows.GetEnvironmentVariable('TEMP', PChar(TempPath), MAX_PATH);
TempPath := PChar(TempPath);
Writeln('TEMP: ' + TempPath);
Windows.GetEnvironmentVariable('TMP', PChar(TempPath), MAX_PATH);
TempPath := PChar(TempPath);
Writeln('TMP: ' + TempPath);
sleep(1000);
ShellExecute(0, PChar('open'), PChar(PathToBDS), Parameters, nil, SW_SHOWNORMAL);
Exit;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln(TempPath);
end.
program DelphiEditorLineEndsTtrRun;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils, ShellApi, IniFiles;
procedure SetTempTmpPath(tempPath, TempSubFolder: string);
var
instName: string;
i: Integer;
function EraseFolder(AFolderName: string; ARemoveFolder: Boolean = True): string;
var
SRec: TSearchRec;
FolderName: string;
begin
Result := '';
if AFolderName = '' then
Exit;
FolderName := IncludeTrailingPathDelimiter(AFolderName);
if FindFirst(FolderName + '*.*', faAnyFile or faDirectory, SRec) = 0 then
begin
repeat
if (SRec.Name <> '.')and(SRec.Name <> '..') then
if SRec.Attr and faDirectory = faDirectory then
Result := EraseFolder(FolderName + SRec.Name, True)
else
if not DeleteFile(FolderName + SRec.Name) then
begin
Writeln('Cannot DeleteFile: ' + FolderName + SRec.Name);
Result := SRec.Name;
end;
if length(Result) > 0 then
exit;
until FindNext(SRec) <> 0;
FindClose(SRec);
end;
if ARemoveFolder then
begin
FolderName := ExcludeTrailingPathDelimiter(FolderName);
if not RemoveDir(FolderName) then
begin
Writeln('Cannot RemoveDir: ' + FolderName);
Result := FolderName;
end;
end;
end;
begin
tempPath := IncludeTrailingPathDelimiter(TempPath) + TempSubFolder;
if not DirectoryExists(tempPath) then
ForceDirectories(tempPath);
if DirectoryExists(tempPath) then
begin
tempPath := IncludeTrailingPathDelimiter(tempPath);
i := 1;
while i < 100 do
begin
instName := 'Inst'+IntToStr(i);
if DirectoryExists(tempPath + instName) then
EraseFolder(tempPath + instName);
Inc(i);
end;
i := 1;
while i < 100 do
begin
instName := 'Inst'+IntToStr(i);
if not DirectoryExists(tempPath + instName) then
break;
Inc(i);
end;
if not DirectoryExists(tempPath + instName) then
begin
ForceDirectories(tempPath + instName);
if DirectoryExists(tempPath + instName) then
begin
Windows.SetEnvironmentVariable('TEMP', PChar(tempPath + instName));
Windows.SetEnvironmentVariable('TMP', PChar(tempPath + instName));
end else
raise Exception.Create('Cannot create: ' + tempPath + instName);
end else
raise Exception.Create('Exists: ' + tempPath + instName);
end else
raise Exception.Create('Not exists: ' + tempPath);
end;
var
TempPath: string;
iniFile: TIniFile;
TempDelphiSubFolder: string;
PathToBDS: PChar;
Parameters: PChar;
pCount: Integer;
begin
try
pCount := ParamCount;
if pCount < 1 then
raise Exception.Create('Need EditorLineEndsTtr.ini section as parameter ');
iniFile := TIniFile.Create(ExtractFilePath(ExcludeTrailingPathDelimiter(ParamStr(0))) + 'EditorLineEndsTtr.ini');
try
TempDelphiSubFolder := iniFile.ReadString(ParamStr(1), 'TempDelphiSubFolder', 'Delphi 2010');
PathToBDS := PChar(iniFile.ReadString(ParamStr(1), 'PathToDelphi', 'C:\Program Files (x86)\Embarcadero\RAD Studio\7.0\bin\bds.exe'));
Parameters := PChar(iniFile.ReadString(ParamStr(1), 'Parameters', '-pDelphi'));
finally
iniFile.Free;
end;
SetLength(TempPath, MAX_PATH);
Windows.GetEnvironmentVariable('TEMP', PChar(TempPath), MAX_PATH);
TempPath := PChar(TempPath);
Writeln('TEMP: ' + TempPath);
Windows.GetEnvironmentVariable('TMP', PChar(TempPath), MAX_PATH);
TempPath := PChar(TempPath);
Writeln('TMP: ' + TempPath);
SetTempTmpPath(TempPath, TempDelphiSubFolder);
Windows.GetEnvironmentVariable('TEMP', PChar(TempPath), MAX_PATH);
TempPath := PChar(TempPath);
Writeln('TEMP: ' + TempPath);
Windows.GetEnvironmentVariable('TMP', PChar(TempPath), MAX_PATH);
TempPath := PChar(TempPath);
Writeln('TMP: ' + TempPath);
sleep(1000);
ShellExecute(0, PChar('open'), PChar(PathToBDS), Parameters, nil, SW_SHOWNORMAL);
Exit;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln(TempPath);
end.
U ini treba da bude recimo za Delphi 2010:
[D2010]
TempDelphiSubFolder=Delphi 2010
PathToDelphi=C:\Program Files (x86)\Embarcadero\RAD Studio\7.0\bin\bds.exe
Parameters=-pDelphi
startuje se: DelphiEditorLineEndsTtrRun D2010