You should start by deriving your classes from the base class
Exception and, preferred, name them starting with an "E" rather than a "T". Since all your exception are basically the same you should create a base class and derive the rest from them:
type
EFileException = class(Exception)
private
FFilename: String;
public
property Filename: String read FFilename write FFilename;
procedure PrintError;
end;
Now, rather than PrintError you should override the base method ToString and, while you're at it, set a new constructor to be able to set the filename at creation time:
type
EFileException = class(Exception)
private
FFilename: String;
public
constructor CreateWithName(const msg: string; const AName: String);
function ToString : String; override;
property Filename: String read FFilename write FFilename;
end;
And now comes the implementation:
{ EFileException }
constructor EFileException.CreateWithName(const msg: string;
const AName: String);
begin
inherited Create(msg);
FFilename := AFilename;
end;
function EFileException.ToString: String;
begin
Result := ClassName + ': ' + FFilename + LineEnding + Message;
end;
Unless you really want (or need) to, don't use constants to explain what the exception is about; instead, since it's used in ToString, let the exception name "explain" itself: for example it's quite clear what EFileNotFound means. That also you to add the user message without cluttering too much the display and, incidentally, scaring the user
Note also that using that base class "as is" you don't have to declare anything else for the derived classes; just doing, e.g.
ECannotReadFile=class(EFileException);
takes care of all, since all have the same basic functionality and using ClassName in the method ToString takes care of diferentiating.
And that's all that comes to mind, though I'm sure I've left out some details