4

I want to open a *.conf file. I want to open this file with the standard Windows editor (e.g., notepad.exe).

I currently have this ShellExecute code:

var
  sPath, conf: String;
begin
  try
  sPath := GetCurrentDir + '\conf\';
  conf := 'nginx.conf';
ShellExecute(Application.Handle, 'open', PChar(conf), '', Pchar(sPath+conf), SW_SHOW);
  except
    ShowMessage('Invalid config path.');
  end;
end; 

But nothing happens. So what should I change?

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Hidden
  • 3,598
  • 4
  • 34
  • 57

3 Answers3

8

How do I open a file with the default text editor?

You need to use ShellExecuteEx and use the lpClass member of SHELLEXECUTEINFO to specify that you want to treat the file as a text file. Like this:

procedure OpenAsTextFile(const FileName: string);
var
  sei: TShellExecuteInfo;
begin
  ZeroMemory(@sei, SizeOf(sei));
  sei.cbSize := SizeOf(sei);
  sei.fMask := SEE_MASK_CLASSNAME;
  sei.lpFile := PChar(FileName);
  sei.lpClass := '.txt';
  sei.nShow := SW_SHOWNORMAL;
  ShellExecuteEx(@sei);
end;

Pass the full path to the file as FileName.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I would probably set the class name to `.txt` instead since `txtfile` is not guaranteed to be the registered progid for text files on all systems. Some apps do change it. – Remy Lebeau Jun 05 '13 at 15:30
  • @RemyLebeau Thank you for that. I confess to knowing little about class names for the shell and defer to your experience and knowledge. – David Heffernan Jun 05 '13 at 15:46
  • actually, I have never had a need to use class names with `ShellExecuteEx()` before. I just commented on what the documentation said (that the class name can be a file extension or a progid) and what I know about how file extension progids work in general. – Remy Lebeau Jun 05 '13 at 17:06
4

The main problem is that you use nginx.conf as the file name. You need the fully-qualified file name (with drive and directory). If the file resides in the same directory as your EXE, you should do

ShellExecute(Handle, nil,
  PChar(ExtractFilePath(Application.ExeName) + 'nginx.conf'),
  nil, nil, SW_SHOWNORMAL)

There is no need to set the directory, and you should normally use SW_SHOWNORMAL.

Also, this only works if the system running the application has the file associations set up properly for .conf files. If the system running the application opens .conf files with MS Paint, then the line above will start MS Paint. If there are no associations at all, the line won't work.

You can specify manually to use notepad.exe:

ShellExecute(Handle, nil, PChar('notepad.exe'),
  PChar(ExtractFilePath(Application.ExeName) + 'nginx.conf'),
  nil, SW_SHOWNORMAL)

Now we start notepad.exe and pass the file name as the first argument.

Third, you shouldn't use try..except the way you do now. The ShellExecute may fail for other reasons than 'invalid config path', and in any case, it won't raise an exception. Instead, consider

if FileExists(...) then
  ShellExecute(...)
else
  MessageBox(Handle, 'Invalid path to configuration file', 'Error', MB_ICONERROR)

Now, back to the main issue. My first code snippet only works if the system running your application happens to have an appropriate file association post for .conf files, while the second will always open Notepad. A better alternative might be to use the application used to open .txt files. David's answer gives an example of this.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • +1 I had not spotted the file name error and assumed that the association was the issue. I will leave my answer since it shows how to make sure that the .conf file is treated as a text file. – David Heffernan Jun 05 '13 at 13:55
  • ShellExecute is a Windows API call that won't raise a Delphi exception in any case. An error is indicated by a return value of <= 32 – Gerry Coll Jun 05 '13 at 14:36
  • In fact error handling for `ShellExecute` is rather hopeless. If you want real error checking you need to use `ShellExecuteEx`. – David Heffernan Jun 05 '13 at 15:44
  • 2
    @Polymorphin On machines that don't have an association for `.conf` (for example the machine I am on right now), the first code sample here will not work. The second sample forces notepad onto the user and I would hate that. I never ever see notepad since that's not my default text editor. What you surely want to do is open the text file with the user's preferred text file editor. – David Heffernan Jun 05 '13 at 15:45
0

use

ShellExecute(0, 'Open', PChar(AFile), nil, '', 1{SW_SHOWNORMAL});

in Delphi DX10 this function defined in

Winapi.ShellAPI

Zam
  • 2,880
  • 1
  • 18
  • 33