Recent

Author Topic: ShellExecute not work with msiexec  (Read 2134 times)

wytwyt02

  • Jr. Member
  • **
  • Posts: 74
ShellExecute not work with msiexec
« on: January 23, 2020, 08:04:57 am »
I have a MYSQL-5.5.60-WINX64.msi file need to be installed with msiexec.

code below:
Code: Pascal  [Select]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   MysqlExeFile: TResourceStream;
  4.   MysqlSavaToFileSteam: TFileStream;
  5.  
  6. begin
  7.   MysqlExeFile:=TResourceStream.Create(HINSTANCE, 'MYSQL-5.5.60-WINX64', RT_RCDATA);
  8.   MysqlSavaToFileSteam:=TFileStream.Create( GetTempDir() + '.\MYSQL.msi', fmCreate);
  9.   MysqlSavaToFileSteam.CopyFrom(MysqlExeFile, 0);
  10.   MysqlSavaToFileSteam.Write(MysqlExeFile.Memory, MysqlExeFile.Size);
  11.   MysqlSavaToFileSteam.Free;
  12.  
  13.   if ShellExecute(0,nil, PChar('"msiexec.exe"'),PChar('"/i MYSQL.msi /passive"'), PChar(GetTempDir()),1) > 32 then begin
  14.     ShowMessage('success');
  15.   end;
  16.  
  17. end;

It always show pararmters error in msiexec, I do not know where is the problem.

wytwyt02

  • Jr. Member
  • **
  • Posts: 74
Re: ShellExecute not work with msiexec
« Reply #1 on: January 23, 2020, 09:49:50 am »
Now I got it:

Code: Pascal  [Select]
  1. ShellExecute(0,nil, PChar('msiexec.exe'),PChar('/i C:\Users\wuao\AppData\Local\Temp\mysql-5.5.60-winx64.msi /passive'), nil,1)

But there a problem comes, ShellExecute return immediately whatever the msi installer is not done, Is there a way like `ShellExecuteAndWait` ?

GetMem

  • Hero Member
  • *****
  • Posts: 3566
Re: ShellExecute not work with msiexec
« Reply #2 on: January 23, 2020, 10:42:58 am »
@wytwyt02
Quote
But there a problem comes, ShellExecute return immediately whatever the msi installer is not done, Is there a way like `ShellExecuteAndWait` ?
Code: Pascal  [Select]
  1. uses JwaWindows, ShellApi;
  2.  
  3. procedure ExecuteAndWait(const AFileName, AParams, ADirectory: WideString;
  4.   const AWaitForProcess: Boolean = True);
  5. var
  6.   SEInfo: TShellExecuteInfoW;
  7.   ExitCode: DWORD;
  8. begin
  9.   FillChar(SEInfo, SizeOf(SEInfo), 0) ;
  10.   SEInfo.cbSize := SizeOf(TShellExecuteInfoW) ;
  11.   with SEInfo do
  12.   begin
  13.     fMask := SEE_MASK_NOCLOSEPROCESS;
  14.     Wnd := Form1.Handle;
  15.     lpFile := PWideChar(AFileName);
  16.     lpParameters := PWideChar(AParams);
  17.     lpDirectory := PWideChar(ADirectory);
  18.     nShow := SW_SHOW;
  19.   end;
  20.   if ShellExecuteExW(@SEInfo) and (AWaitForProcess) then
  21.   begin
  22.     repeat
  23.       Application.ProcessMessages;
  24.       GetExitCodeProcess(SEInfo.hProcess, ExitCode) ;
  25.     until (ExitCode <> STILL_ACTIVE) or  Application.Terminated;
  26.   end;
  27. end;

wytwyt02

  • Jr. Member
  • **
  • Posts: 74
Re: ShellExecute not work with msiexec
« Reply #3 on: January 23, 2020, 12:08:04 pm »
@wytwyt02
Quote
But there a problem comes, ShellExecute return immediately whatever the msi installer is not done, Is there a way like `ShellExecuteAndWait` ?
Code: Pascal  [Select]
  1. uses JwaWindows, ShellApi;
  2.  
  3. procedure ExecuteAndWait(const AFileName, AParams, ADirectory: WideString;
  4.   const AWaitForProcess: Boolean = True);
  5. var
  6.   SEInfo: TShellExecuteInfoW;
  7.   ExitCode: DWORD;
  8. begin
  9.   FillChar(SEInfo, SizeOf(SEInfo), 0) ;
  10.   SEInfo.cbSize := SizeOf(TShellExecuteInfoW) ;
  11.   with SEInfo do
  12.   begin
  13.     fMask := SEE_MASK_NOCLOSEPROCESS;
  14.     Wnd := Form1.Handle;
  15.     lpFile := PWideChar(AFileName);
  16.     lpParameters := PWideChar(AParams);
  17.     lpDirectory := PWideChar(ADirectory);
  18.     nShow := SW_SHOW;
  19.   end;
  20.   if ShellExecuteExW(@SEInfo) and (AWaitForProcess) then
  21.   begin
  22.     repeat
  23.       Application.ProcessMessages;
  24.       GetExitCodeProcess(SEInfo.hProcess, ExitCode) ;
  25.     until (ExitCode <> STILL_ACTIVE) or  Application.Terminated;
  26.   end;
  27. end;

Thanks,I got it from https://stackoverflow.com/questions/17638674/how-to-wait-for-shellexecute-to-run, It seems better than your code. :)

wp

  • Hero Member
  • *****
  • Posts: 6726
Re: ShellExecute not work with msiexec
« Reply #4 on: January 23, 2020, 12:20:49 pm »
Why not use TProcess and its option poWaitOnExit? https://wiki.freepascal.org/Executing_External_Programs#TProcess
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

wytwyt02

  • Jr. Member
  • **
  • Posts: 74
Re: ShellExecute not work with msiexec
« Reply #5 on: January 23, 2020, 12:40:02 pm »

wytwyt02

  • Jr. Member
  • **
  • Posts: 74
Re: ShellExecute not work with msiexec
« Reply #6 on: January 23, 2020, 02:27:10 pm »
Why not use TProcess and its option poWaitOnExit? https://wiki.freepascal.org/Executing_External_Programs#TProcess

Hi, I have tried with TProcess, but msiexec.exe paramters show paramters error dialog to me.

 
Code: Pascal  [Select]
  1.   MySQLInstallProcess := TProcess.Create(nil);
  2.   MySQLInstallProcess.Executable := 'msiexec.exe';
  3.   MySQLInstallProcess.Parameters.Add(
  4.     '/i C:\Users\wuao\AppData\Local\Temp\MYSQL.msi /passive');
  5.   MySQLInstallProcess.Options := MySQLInstallProcess.Options + [poWaitOnExit];
  6.   MySQLInstallProcess.Execute;
  7.   MySQLInstallProcess.Free;
  8.  

wp

  • Hero Member
  • *****
  • Posts: 6726
Re: ShellExecute not work with msiexec
« Reply #7 on: January 23, 2020, 03:12:09 pm »
I have tried with TProcess, but msiexec.exe paramters show paramters error dialog to me.
Code: Pascal  [Select]
  1. ...
  2.   MySQLInstallProcess.Parameters.Add(
  3.     '/i C:\Users\wuao\AppData\Local\Temp\MYSQL.msi /passive');
  4.  
You must add parameters one by one, i.e.
Code: Pascal  [Select]
  1. ...
  2.   MySQLInstallProcess.Parameters.Add('/i');
  3.   MySQLInstallProcess.Parameters.Add('C:\Users\wuao\AppData\Local\Temp\MYSQL.msi');
  4.   MySQLInstallProcess.Parameters.Add('/passive');
I am not 100% sure about what exactly a "parameter" is: Maybe the '/' must be omitted? And maybe the '/i' and 'C:\Users\...' must be merged to ...Parameters.Add('/i C:\Users\wuoa\AppData\Local\temp\MySQL.msi') -- but this is only a few combinations which you easily can sort out.

And there is also a deprecated syntax in which the entire command line is passed to parameter "Command line" instead of .Executeable and Parameters.Add, e.g.
Code: Pascal  [Select]
  1.   MySQLInstallProcess.CommandLine := 'msiexec.exe /i C:\Users\wuao\AppData\Local\Temp\MYSQL.msi /passive';
  2.  
As I said this is deprecated, but it is worth a try to see if TProcess is doing what you need.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7934
Re: ShellExecute not work with msiexec
« Reply #8 on: January 23, 2020, 03:24:03 pm »
Sounds all so complicated

wp: the separate parameter is like splitting the deprecated commandline on space. It however is easier to describe complicated variants since it doesn't require all kinds of odd ball quoting rules. (which are even more complicated if you try to do it multiplatform)

But in this case tprocess is overkill.

Code: Pascal  [Select]
  1. ExecuteProcess('msiexec.exe',['/i','C:\Users\wuao\AppData\Local\Temp\MYSQL.msi','/passive']);

should do the trick.

wytwyt02

  • Jr. Member
  • **
  • Posts: 74
Re: ShellExecute not work with msiexec
« Reply #9 on: January 24, 2020, 03:09:34 am »
I have tried with TProcess, but msiexec.exe paramters show paramters error dialog to me.
Code: Pascal  [Select]
  1. ...
  2.   MySQLInstallProcess.Parameters.Add(
  3.     '/i C:\Users\wuao\AppData\Local\Temp\MYSQL.msi /passive');
  4.  
You must add parameters one by one, i.e.
Code: Pascal  [Select]
  1. ...
  2.   MySQLInstallProcess.Parameters.Add('/i');
  3.   MySQLInstallProcess.Parameters.Add('C:\Users\wuao\AppData\Local\Temp\MYSQL.msi');
  4.   MySQLInstallProcess.Parameters.Add('/passive');
I am not 100% sure about what exactly a "parameter" is: Maybe the '/' must be omitted? And maybe the '/i' and 'C:\Users\...' must be merged to ...Parameters.Add('/i C:\Users\wuoa\AppData\Local\temp\MySQL.msi') -- but this is only a few combinations which you easily can sort out.

And there is also a deprecated syntax in which the entire command line is passed to parameter "Command line" instead of .Executeable and Parameters.Add, e.g.
Code: Pascal  [Select]
  1.   MySQLInstallProcess.CommandLine := 'msiexec.exe /i C:\Users\wuao\AppData\Local\Temp\MYSQL.msi /passive';
  2.  
As I said this is deprecated, but it is worth a try to see if TProcess is doing what you need.
Now I have problem with MySQLInstanceConfig.exe:

 
Code: Pascal  [Select]
  1. ConfigurationProcess:=TProcess.Create(nil);
  2.   ConfigurationProcess.Executable:='.\MySQLInstanceConfig.exe';
  3.   ConfigurationProcess.CurrentDirectory:='C:\Program Files\MySQL\MySQL Server 5.5\bin';
  4.   ConfigurationProcess.Parameters.Add('-i');
  5.   ConfigurationProcess.Parameters.Add('-q');
  6.   ConfigurationProcess.Parameters.Add('"-lC:\mysql_install_log.txt"');
  7.   ConfigurationProcess.Parameters.Add('"-nMySQL Server 5.5"');
  8.   ConfigurationProcess.Parameters.Add('"-pC:\Program Files\MySQL\MySQL Server 5.5"');
  9.   ConfigurationProcess.Parameters.Add('-v');
  10.   ConfigurationProcess.Parameters.Add('5.5.60');
  11.   ConfigurationProcess.Parameters.Add('ServerType=DEVELOPMEN');
  12.   ConfigurationProcess.Parameters.Add('DatabaseType=MIXED');
  13.   ConfigurationProcess.Parameters.Add('ConnectionUsage=DSS');
  14.   ConfigurationProcess.Parameters.Add('Port=3306');
  15.   ConfigurationProcess.Parameters.Add('ServiceName=MySQL5.5');
  16.   ConfigurationProcess.Parameters.Add('RootPassword=root');
  17.   ConfigurationProcess.Parameters.Add('ConnectionCount=50');
  18.   ConfigurationProcess.Parameters.Add('Charset=gbk');
  19.   ConfigurationProcess.Options := ConfigurationProcess.Options + [poWaitOnExit];
  20.   ConfigurationProcess.Execute;
  21.   ConfigurationProcess.Free;
  22.  

There is a exception when ConfigurationProcess.Execute,  It might Parameters problem, I do not know how to fix. And I think TProcess.Parameters.Add is unnecessary, Not Convenient
« Last Edit: January 24, 2020, 03:13:15 am by wytwyt02 »

winni

  • Hero Member
  • *****
  • Posts: 898
Re: ShellExecute not work with msiexec
« Reply #10 on: January 24, 2020, 03:26:11 am »
Hi!

I think you should by a 'T' for DEVELOPMENT

Code: Pascal  [Select]
  1. ConfigurationProcess.Parameters.Add('ServerType=DEVELOPMEN');

Winni

PascalDragon

  • Hero Member
  • *****
  • Posts: 968
  • Compiler Developer
Re: ShellExecute not work with msiexec
« Reply #11 on: January 24, 2020, 09:36:18 am »
Now I have problem with MySQLInstanceConfig.exe:

 
Code: Pascal  [Select]
  1. ConfigurationProcess:=TProcess.Create(nil);
  2.   ConfigurationProcess.Executable:='.\MySQLInstanceConfig.exe';
  3.   ConfigurationProcess.CurrentDirectory:='C:\Program Files\MySQL\MySQL Server 5.5\bin';
  4.   ConfigurationProcess.Parameters.Add('-i');
  5.   ConfigurationProcess.Parameters.Add('-q');
  6.   ConfigurationProcess.Parameters.Add('"-lC:\mysql_install_log.txt"');
  7.   ConfigurationProcess.Parameters.Add('"-nMySQL Server 5.5"');
  8.   ConfigurationProcess.Parameters.Add('"-pC:\Program Files\MySQL\MySQL Server 5.5"');
  9.   ConfigurationProcess.Parameters.Add('-v');
  10.   ConfigurationProcess.Parameters.Add('5.5.60');
  11.   ConfigurationProcess.Parameters.Add('ServerType=DEVELOPMEN');
  12.   ConfigurationProcess.Parameters.Add('DatabaseType=MIXED');
  13.   ConfigurationProcess.Parameters.Add('ConnectionUsage=DSS');
  14.   ConfigurationProcess.Parameters.Add('Port=3306');
  15.   ConfigurationProcess.Parameters.Add('ServiceName=MySQL5.5');
  16.   ConfigurationProcess.Parameters.Add('RootPassword=root');
  17.   ConfigurationProcess.Parameters.Add('ConnectionCount=50');
  18.   ConfigurationProcess.Parameters.Add('Charset=gbk');
  19.   ConfigurationProcess.Options := ConfigurationProcess.Options + [poWaitOnExit];
  20.   ConfigurationProcess.Execute;
  21.   ConfigurationProcess.Free;
  22.  

There is a exception when ConfigurationProcess.Execute,  It might Parameters problem, I do not know how to fix. And I think TProcess.Parameters.Add is unnecessary, Not Convenient

I can't help you regarding the exception, but you'll notice the convenience if you adjust your code:

Code: Pascal  [Select]
  1.   ConfigurationProcess.Parameters.Add('-lC:\mysql_install_log.txt');
  2.   ConfigurationProcess.Parameters.Add('-nMySQL Server 5.5');
  3.   ConfigurationProcess.Parameters.Add('-pC:\Program Files\MySQL\MySQL Server 5.5');
  4.  

Notice the missing quotation marks. TProcess will insert them by itself.

And you can also shorting the code a bit more (as you don't reference the process somewhere else):

Code: Pascal  [Select]
  1.   with TProcess.Create(Nil) do
  2.     try
  3.       Executable := '.\MySQLInstanceConfig.exe';
  4.       CurrentDirectory := 'C:\Program Files\MySQL\MySQL Server 5.5\bin';
  5.       with Parameters do begin
  6.         Add('-i');
  7.         Add('-q');
  8.         // etc.
  9.       end;
  10.       Options := Options + [poWaitOnExit];
  11.       Execute;
  12.     finally
  13.       Free;
  14.     end;
  15.  

Note: the tryfinally block is also called a resource protection block and ensures that the Free is executed even if an exception is raised between try and finally.

wytwyt02

  • Jr. Member
  • **
  • Posts: 74
Re: ShellExecute not work with msiexec
« Reply #12 on: January 24, 2020, 10:09:00 am »
Now I have problem with MySQLInstanceConfig.exe:

 
Code: Pascal  [Select]
  1. ConfigurationProcess:=TProcess.Create(nil);
  2.   ConfigurationProcess.Executable:='.\MySQLInstanceConfig.exe';
  3.   ConfigurationProcess.CurrentDirectory:='C:\Program Files\MySQL\MySQL Server 5.5\bin';
  4.   ConfigurationProcess.Parameters.Add('-i');
  5.   ConfigurationProcess.Parameters.Add('-q');
  6.   ConfigurationProcess.Parameters.Add('"-lC:\mysql_install_log.txt"');
  7.   ConfigurationProcess.Parameters.Add('"-nMySQL Server 5.5"');
  8.   ConfigurationProcess.Parameters.Add('"-pC:\Program Files\MySQL\MySQL Server 5.5"');
  9.   ConfigurationProcess.Parameters.Add('-v');
  10.   ConfigurationProcess.Parameters.Add('5.5.60');
  11.   ConfigurationProcess.Parameters.Add('ServerType=DEVELOPMEN');
  12.   ConfigurationProcess.Parameters.Add('DatabaseType=MIXED');
  13.   ConfigurationProcess.Parameters.Add('ConnectionUsage=DSS');
  14.   ConfigurationProcess.Parameters.Add('Port=3306');
  15.   ConfigurationProcess.Parameters.Add('ServiceName=MySQL5.5');
  16.   ConfigurationProcess.Parameters.Add('RootPassword=root');
  17.   ConfigurationProcess.Parameters.Add('ConnectionCount=50');
  18.   ConfigurationProcess.Parameters.Add('Charset=gbk');
  19.   ConfigurationProcess.Options := ConfigurationProcess.Options + [poWaitOnExit];
  20.   ConfigurationProcess.Execute;
  21.   ConfigurationProcess.Free;
  22.  

There is a exception when ConfigurationProcess.Execute,  It might Parameters problem, I do not know how to fix. And I think TProcess.Parameters.Add is unnecessary, Not Convenient

I can't help you regarding the exception, but you'll notice the convenience if you adjust your code:

Code: Pascal  [Select]
  1.   ConfigurationProcess.Parameters.Add('-lC:\mysql_install_log.txt');
  2.   ConfigurationProcess.Parameters.Add('-nMySQL Server 5.5');
  3.   ConfigurationProcess.Parameters.Add('-pC:\Program Files\MySQL\MySQL Server 5.5');
  4.  

Notice the missing quotation marks. TProcess will insert them by itself.

And you can also shorting the code a bit more (as you don't reference the process somewhere else):

Code: Pascal  [Select]
  1.   with TProcess.Create(Nil) do
  2.     try
  3.       Executable := '.\MySQLInstanceConfig.exe';
  4.       CurrentDirectory := 'C:\Program Files\MySQL\MySQL Server 5.5\bin';
  5.       with Parameters do begin
  6.         Add('-i');
  7.         Add('-q');
  8.         // etc.
  9.       end;
  10.       Options := Options + [poWaitOnExit];
  11.       Execute;
  12.     finally
  13.       Free;
  14.     end;
  15.  

Note: the tryfinally block is also called a resource protection block and ensures that the Free is executed even if an exception is raised between try and finally.

Thanks, Your code is more clear, And I notice there is a TProcess.Stderr Stream, I wanna to figure out what's the problem, How to redirect the TProcess.Stderr to a TFileStream?

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7934
Re: ShellExecute not work with msiexec
« Reply #13 on: January 24, 2020, 11:37:02 am »
See the large output scheme. You will need to enter a loop and drain output and stderr regularly and write it to whatever stream you want.

wytwyt02

  • Jr. Member
  • **
  • Posts: 74
Re: ShellExecute not work with msiexec
« Reply #14 on: January 24, 2020, 12:13:36 pm »
Sounds all so complicated

wp: the separate parameter is like splitting the deprecated commandline on space. It however is easier to describe complicated variants since it doesn't require all kinds of odd ball quoting rules. (which are even more complicated if you try to do it multiplatform)

But in this case tprocess is overkill.

Code: Pascal  [Select]
  1. ExecuteProcess('msiexec.exe',['/i','C:\Users\wuao\AppData\Local\Temp\MYSQL.msi','/passive']);

should do the trick.

Hi, Mysql msi installed success, Now I need to config the mysql instance, MySQL provide a toll called MySQLInstanceConfig.exe to config, So I tried with:

Code: Pascal  [Select]
  1. ExecuteProcess('F:\MySQLInstanceConfig.exe', ''); // omit the paramaters will use GUI instead of command line for simplfied demonstration.
  2.  

Still exception with EOSError Exception:

Code: Pascal  [Select]
  1. [Debugger Exception Notification]
  2.  
  3. Project project1 raised exception class 'EOSError' with message:
  4. Failed to execute ""F:\MySQLInstanceConfig.exe"
  5.  

TProcess throw exception too.

But If I use ShellExecuteExA will works:

 
Code: Pascal  [Select]
  1.  
  2.   with ConfigEXEINFO do
  3.   begin
  4.     cbSize:=SizeOf(ConfigEXEINFO);
  5.     fMask:=SEE_MASK_NOCLOSEPROCESS;
  6.     wnd:=0;
  7.     lpVerb:=nil;
  8.     lpFile:='.\MySQLInstanceConfig.exe';
  9.     lpParameters:=''; //omit the parameters
  10.     lpDirectory:='F:';
  11.     nShow:=SW_HIDE;
  12.     hInstApp:=0;
  13.   end;
  14.  
  15.   ShellExecuteExA(@ConfigEXEINFO);
  16.  

I upload the to MySQLInstanceConfig.exe Mega cloud disk, You might try: https://mega.nz/#!Fowj1aiT!VK0s1JPOW6wNUT3_ctd5s1hw3wHfjLNiHGTw0gKhwuw
« Last Edit: January 24, 2020, 12:29:06 pm by wytwyt02 »