Jump to content
aehimself

How to open a file in the already running IDE?

Recommended Posts

I'm building a tool which searches for and opens Delphi source files. Until now execution was a simple ShellExecute call to the .pas file and everything was working just file.

Now, as a second Delphi version is introduced I had to change the code to support opening said file in a specific Delphi version. My issue is that a simple call to bds.exe will always launch a new Delphi instance, and I need to re-use the one currently running. Basically I need to mimic the IDEs behavior when double-clicking a .pas file in Explorer.

 

Unfortunately I could not find any documentation about the parameters of BDSLauncher, nor any relevant parameters of Bds.exe which could achieve this. I also built a small program which only lists the parameters it was started with and temporarily replaced BdsLauncher.exe and then bds.exe to see what it received when something is double-clicked, but all I got was the full path of bds.exe.

 

Can anyone point me to the right direction?

 

Thanks!

Share this post


Link to post
22 minutes ago, aehimself said:

Can anyone point me to the right direction?

I think that it's not problem with your code, but with REGISTRY definitions to RAD Studio!

 

I think that you needs pay attention if your "IDE" is registering "* files using by RAD" in Tools->IDE->File Associaton = *

  • I once had a problem that when I clicked on a ".pas" file (for example), the O.S. insisted on opening a new session for a new "IDE RAD Studio", even with the option above set to "all files associated with RAD Studio"...
    In short, I had to "deselect" and "select" the above option again, in order for the REGISTRY to be updated!

  • From there, everything went back to working as expected!

image.png.228ec08e03596f26edb0433564dc8e9c.png

 

So maybe this can help you with this task!

  • UnSelect and Re-Select again the option and try your tool!
Edited by programmerdelphi2k

Share this post


Link to post

here, a code from @David Heffernan on StackOverFlow that works like a charm

https://stackoverflow.com/questions/16941455/how-do-i-open-a-file-with-the-default-text-editor

procedure TForm1.Button1Click(Sender: TObject);
var
  sei: TShellExecuteInfo;
begin
  ZeroMemory(@sei, SizeOf(sei));
  sei.cbSize := SizeOf(sei);
  sei.fMask := SEE_MASK_CLASSNAME;
  sei.lpFile := PChar('d:\myfile.pas');
  sei.lpClass := '.pas';
  sei.nShow := SW_SHOWNORMAL;
  ShellExecuteEx(@sei);
end;

or just: PChar or PWideChar ?

procedure TForm1.Button2Click(Sender: TObject);
var
  LOperation: PWideChar;
  LExec      : PWideChar;
  LParams     : PWideChar;
  LDirWork  : PWideChar;
begin
  LOperation := PWideChar('open');
  LExec       := PWideChar('d:\myfile.pas');
  LParams      := PWideChar('');
  LDirWork   := PWideChar('d:\');
  //
  ShellExecute(Handle, LOperation, LExec, LParams, LDirWork, SW_SHOWNORMAL)
end;

 

Edited by programmerdelphi2k

Share this post


Link to post

Please read the question again. To be able to launch with a specific Delphi version you need to start bds.exe, not just the .pas file; this is how it was until now.

Share this post


Link to post

use "o BDS path\exe" as your first param, and the file name .pas as second! then, you "force" use only "bdsXXX" to open file.pas!

  • dont forget: qualify the paths!
Edited by programmerdelphi2k

Share this post


Link to post

This is exactly what I did. This introduces the new instance issue, which this topic is about.

I'm probably missing a parameter - I just don't know which.

Share this post


Link to post
35 minutes ago, aehimself said:

I'm probably missing a parameter - I just don't know which.

you have to start the bdslauncher not the bds, theoretically, on my install it stopped working completely couple of months ago.

Share this post


Link to post

  LOperation := PWideChar('open');
  LExec      := PWideChar('C:\RADStudio\RX112\bin\bdslauncher.exe');  // dont works for here, nothing is opened!!! no error at all!
  LParams    := PWideChar('d:\myfile.pas');
  LDirWork   := ''; // PWideChar('d:\');
  //
  ShellExecute(Handle, LOperation, LExec, LParams, LDirWork, SW_SHOWNORMAL)
 

Share this post


Link to post
20 minutes ago, programmerdelphi2k said:

dont works for here, nothing is opened!!!

what about bdslauncher.exe bds.exe /np d:\myfile.pas

?

 

with full paths ofc

 

Edited by Attila Kovacs

Share this post


Link to post
15 minutes ago, Attila Kovacs said:

what about bdslauncher.exe bds.exe /np d:\myfile.pas

?

 

with full paths ofc

 

Tried. Bds.exe never starts, bdslauncher.exe never quits, just hangs. No windows, no errors, nothing.

Also tried adding the necessary (?) -pDelphi switch, same result. Tried giving these parameters only to Bdslauncher and only the source file. No effect.

Edited by aehimself

Share this post


Link to post

nop!

procedure TForm1.Button2Click(Sender: TObject);
var
  LOperation: PWideChar;
  LExec     : PWideChar;
  LParams   : PWideChar;
  LDirWork  : PWideChar;
begin
  LOperation := PWideChar('open');
  LExec      := PWideChar('C:\RADStudio\RX112\bin\bdslauncher.exe BDS.EXE /np d:\myfile.pas');
  LParams    := ''; // PWideChar('d:\myfile.pas');
  LDirWork   := ''; // PWideChar('d:\');
  //
  ShellExecute(Handle, LOperation, LExec, LParams, LDirWork, SW_SHOWNORMAL)
end;

 

but this works with IDE on memory or not!

 

procedure TForm1.Button1Click(Sender: TObject);
var
  LShExecInfo    : TShellExecuteInfo;
  LShExecInfoSize: NativeUInt;
  LWinReg        : TRegistry;
  LHKEY          : HKEY;
  // LKeyString     : string;
begin
  // "App"="c:\\radstudio\\rx112\\bin\\bds.exe"
  // C:\RADStudio\RX112\bin\bds.exe "-pDelphi" -np
  LHKEY   := 0;
  LWinReg := TRegistry.Create;
  try
    if LWinReg.KeyExists('HKEY_CURRENT_USER\SOFTWARE\Embarcadero\BDS\22.0') then
      begin
        LWinReg.OpenKeyReadOnly('HKEY_CURRENT_USER\SOFTWARE\Embarcadero\BDS\22.0');
        LHKEY := LWinReg.CurrentKey;
        // LKeyString := LWinReg.ReadString('App');
      end;
    //
    LShExecInfoSize := SizeOf(LShExecInfo); // 60...
    //
    ZeroMemory(@LShExecInfo, LShExecInfoSize);
    //
    LShExecInfo.cbSize    := SizeOf(LShExecInfo);
    LShExecInfo.fMask     := SEE_MASK_CLASSNAME; // or SEE_MASK_CLASSKEY;
    LShExecInfo.lpFile    := PChar('d:\myfile.pas');
    LShExecInfo.lpClass   := '.pas';
    LShExecInfo.hkeyClass := LHKEY;
    LShExecInfo.nShow     := SW_SHOWNORMAL;
    //
    ShellExecuteEx(@LShExecInfo);
  finally
    LWinReg.Free;
  end;
end;

 

Share this post


Link to post
4 minutes ago, programmerdelphi2k said:

LExec := PWideChar('C:\RADStudio\RX112\bin\bdslauncher.exe BDS.EXE /np d:\myfile.pas');

with full path of bds.exe?

Share this post


Link to post

nop!

  LOperation := PWideChar('open');
  LExec      := PWideChar('C:\RADStudio\RX112\bin\BDSLauncher.exe C:\RADStudio\RX112\bin\BDS.EXE /np D:\myfile.pas ');  // DOESNT WORKS TOO! at least here!
  LParams    := ''; // PWideChar('d:\myfile.pas');
  LDirWork   := ''; // PWideChar('d:\');
  //
  ShellExecute(Handle, LOperation, LExec, LParams, LDirWork, SW_SHOWNORMAL)
 

image.thumb.png.4c4a044ad5cdde729a267ce49de87bfe.png

Edited by programmerdelphi2k
  • Like 1

Share this post


Link to post
24 minutes ago, programmerdelphi2k said:

but this works with IDE on memory or not!

That is really surprising as that's not how you open a registry key with TRegistry AND even if you correct that, reg.CurrentKey won't be changed after a single .OpenReadOnly.

 

Running the code on a PC with Delphi 10.4 and 11 installed also confirms failure: it opens up the file in Delphi 10.4.

Edited by aehimself

Share this post


Link to post

sorry, on copy I did wrong ... but the result is the same = WORKS!

 

  LWinReg := TRegistry.Create;
  try
    LWinReg.RootKey := HKEY_CURRENT_USER;
    if LWinReg.KeyExists('SOFTWARE\Embarcadero\BDS\22.0') then
      begin
        if LWinReg.OpenKeyReadOnly('SOFTWARE\Embarcadero\BDS\22.0') then
 

Edited by programmerdelphi2k

Share this post


Link to post
11 minutes ago, programmerdelphi2k said:

sorry, on copy I did wrong ... but the result is the same = WORKS!

No, it does not 🙂 First, CurrentKey has a zero value after .OpenKeyReadOnly. Second, you are assigning a wrong registry path, not what the API expects:

 

https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-shellexecuteinfoa

 

hkeyClass

Type: HKEY

A handle to the registry key for the file type. The access rights for this registry key should be set to KEY_READ. This member is ignored if fMask does not include SEE_MASK_CLASSKEY.

 

Edit: wrong parameter copied

Edited by aehimself

Share this post


Link to post
3 hours ago, programmerdelphi2k said:

here, a code from @David Heffernan on StackOverFlow that works like a charm

https://stackoverflow.com/questions/16941455/how-do-i-open-a-file-with-the-default-text-editor


procedure TForm1.Button1Click(Sender: TObject);
var
  sei: TShellExecuteInfo;
begin
  ZeroMemory(@sei, SizeOf(sei));
  sei.cbSize := SizeOf(sei);
  sei.fMask := SEE_MASK_CLASSNAME;
  sei.lpFile := PChar('d:\myfile.pas');
  sei.lpClass := '.pas';
  sei.nShow := SW_SHOWNORMAL;
  ShellExecuteEx(@sei);
end;

or just: PChar or PWideChar ?


procedure TForm1.Button2Click(Sender: TObject);
var
  LOperation: PWideChar;
  LExec      : PWideChar;
  LParams     : PWideChar;
  LDirWork  : PWideChar;
begin
  LOperation := PWideChar('open');
  LExec       := PWideChar('d:\myfile.pas');
  LParams      := PWideChar('');
  LDirWork   := PWideChar('d:\');
  //
  ShellExecute(Handle, LOperation, LExec, LParams, LDirWork, SW_SHOWNORMAL)
end;

 

Oh how it pains me to see my name in a post with a call to ShellExecute. That function should never be called because it doesn't offer proper handling of errors. Although it also shames me that my SO answer doesn't handle errors. 

Share this post


Link to post

Je suis désolé, mais mon "français" n'est pas très bon et Google n'était pas disponible à ce moment

by Google, it would be: c'est la vie mon cherie

Edited by programmerdelphi2k

Share this post


Link to post
19 minutes ago, programmerdelphi2k said:

Je suis désolé, mais mon "français" n'est pas très bon et Google n'était pas disponible à ce moment

by Google, it would be: c'est la vie mon cherie

ma chérie

mon chéri

 

I am male, as you can infer from my forename. Therefore you use mon chéri. 

 

https://www.larousse.fr/dictionnaires/francais/chéri/15145

 

I'm surprised that Google translate gets this wrong. Although perhaps my French is even worse than I think it is! 

Edited by David Heffernan

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Ă—