aehimself 396 Posted December 5, 2022 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
programmerdelphi2k 237 Posted December 5, 2022 (edited) 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! Â So maybe this can help you with this task! UnSelect and Re-Select again the option and try your tool! Edited December 5, 2022 by programmerdelphi2k Share this post Link to post
programmerdelphi2k 237 Posted December 5, 2022 (edited) 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 December 5, 2022 by programmerdelphi2k Share this post Link to post
aehimself 396 Posted December 5, 2022 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
programmerdelphi2k 237 Posted December 5, 2022 (edited) 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 December 5, 2022 by programmerdelphi2k Share this post Link to post
aehimself 396 Posted December 5, 2022 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
programmerdelphi2k 237 Posted December 5, 2022 LShExecInfo.hkeyClass == use Registry definition... maybe you can use the key where is definide the "exe from RAD" desired!!! --> try some like this! Share this post Link to post
Attila Kovacs 629 Posted December 5, 2022 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
programmerdelphi2k 237 Posted December 5, 2022  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
programmerdelphi2k 237 Posted December 5, 2022 in my test, would be necessary "Create a process" or verify if the "Process X" in opened on memory"... then, use this ID to open your file! Share this post Link to post
Attila Kovacs 629 Posted December 5, 2022 (edited) 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 December 5, 2022 by Attila Kovacs Share this post Link to post
aehimself 396 Posted December 5, 2022 (edited) 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 December 5, 2022 by aehimself Share this post Link to post
programmerdelphi2k 237 Posted December 5, 2022 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
Attila Kovacs 629 Posted December 5, 2022 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
programmerdelphi2k 237 Posted December 5, 2022 (edited) 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)  Edited December 5, 2022 by programmerdelphi2k 1 Share this post Link to post
programmerdelphi2k 237 Posted December 5, 2022 according with "Raymond Chen" MVP MS, it's ShellExecute is a "little box" very complicate to understand an easy to use! Share this post Link to post
aehimself 396 Posted December 5, 2022 (edited) 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 December 5, 2022 by aehimself Share this post Link to post
programmerdelphi2k 237 Posted December 5, 2022 (edited) 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 December 5, 2022 by programmerdelphi2k Share this post Link to post
aehimself 396 Posted December 5, 2022 (edited) 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 December 5, 2022 by aehimself Share this post Link to post
David Heffernan 2345 Posted December 5, 2022 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
David Heffernan 2345 Posted December 5, 2022 58 minutes ago, programmerdelphi2k said: cest la vie, mon cherry! mon chéri Share this post Link to post
Attila Kovacs 629 Posted December 5, 2022 10 minutes ago, David Heffernan said: mon chéri perhaps he has a Cherry keyboard... Share this post Link to post
programmerdelphi2k 237 Posted December 5, 2022 (edited) 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 December 5, 2022 by programmerdelphi2k Share this post Link to post
David Heffernan 2345 Posted December 5, 2022 (edited) 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 December 5, 2022 by David Heffernan Share this post Link to post