Creating run-time bat and process in delphi

4

I have two functions that create a file bat and execute it, but I just can not create the process ( CreateProcess returns False ) and I can not identify the error.

I use Windows 7, 64-bit. Should I change some parameter in the WinExecAndWait32 function? How to debug CreateProcess ?

Note: The same function worked on XE5.

This is the function that creates the file bat , executes it, and then deletes it:

function AddDeleteServico(comando: string): boolean;
var
   txt: TextFile;
   dir: string;
   ret: boolean;
begin
  ret:=False;
  try
     dir:=ExtractFilePath(Application.ExeName);
     AssignFile(txt, dir + 'meu.bat');
     Rewrite(txt);
     Write(txt,comando);

     CloseFile(txt);
     if WinExecAndWait32(dir + 'meu.bat',dir,SW_ShowNormal) = 0 then
         ret:=True;
     DeleteFile(PChar(dir + 'meu.bat'));
  finally
     AddDeleteServico:=ret;
  end;
end;

This is the function that creates the process:

** EDIT: ** After the help of the colleagues she functioned like this:

 function WinExecAndWait32(ExeName: string; CmdLineArgs: string = '';
  ShowWindow: boolean = True; WaitForFinish: boolean = False): integer;
var
  StartInfo: TStartupInfo;
  ProcInfo: TProcessInformation;
begin

  FillChar(StartInfo,SizeOf(TStartupInfo),#0);
  FillChar(ProcInfo,SizeOf(TProcessInformation),#0);
  StartInfo.cb := SizeOf(TStartupInfo);

  if not(ShowWindow) then begin
    StartInfo.dwFlags := STARTF_USESHOWWINDOW;
    StartInfo.wShowWindow := SW_HIDE;
  end;

  CreateProcess(nil,PChar(ExeName + ' ' + CmdLineArgs),nil,nil,False,
    CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS,nil,nil,StartInfo,
    ProcInfo);

  Result := ProcInfo.dwProcessId;

  if WaitForFinish then begin
    WaitForSingleObject(ProcInfo.hProcess,Infinite);
  end;

  CloseHandle(ProcInfo.hProcess);
  CloseHandle(ProcInfo.hThread);
end;
    
asked by anonymous 29.03.2015 / 05:20

1 answer

3

A bat file is not an executable. Like sh , it is just a text file, which needs to be interpreted and then its commands are executed by the interpreter.

However, Linux, Windows does not know how to choose an interpreter to run it directly (at least not the traditional process creation functions), and there is no mechanism to find out which interpreter to use to run the program (this is the function of the line #!/bin/sh in the files sh and in others).

So in Windows, you need to invoke the interpreter to run bat . On Linux, this program would be bash (or equivalent). On Windows, it is cmd.exe .

So, your command should execute cmd and pass parameter bat to be executed. I modified its original function to do this. I did not test it, because I do not have Delphi installed (nor Lazarus), but the concept is this. I also added the commands to close the created handles, as comments in the question.

function WinExecBatAndWait(FileName: String; WorkDir: String; Visibility: integer): integer;
var
   zAppName: PChar;
   zCurDir: PChar;
   StartupInfo: TStartupInfo;
   ProcessInfo: TProcessInformation;
begin
  // necessário executar o cmd.exe!
  FileName:= GetEnvironmentVariable('COMSPEC') + ' /C ' + FileName;
  zAppName:= PChar(FileName);
  zCurDir:= PChar(WorkDir);
  FillChar(StartupInfo,Sizeof(StartupInfo),#0);
  StartupInfo.cb:=Sizeof(StartupInfo);
  StartupInfo.dwFlags:=STARTF_USESHOWWINDOW;
  StartupInfo.wShowWindow:=Visibility;

  if not CreateProcess(nil,zAppName,nil,nil,False,CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS,nil,zCurDir,StartupInfo,ProcessInfo) then
     Result:=-1
  else
  begin
     WaitforSingleObject(ProcessInfo.hProcess,INFINITE);
     GetExitCodeProcess(ProcessInfo.hProcess,DWORD(Result));
     CloseHandle(ProcessInfo.hProcess);''CloseHandle(ProcessInfo.hThread);
  end;
end;

Do not forget that it may be necessary to add " to the arguments if they have spaces!

"But when I double-click the file on my desktop it runs!"

What happens is that the shell (executed by the first instance of the application explorer.exe in the user) knows which interpreter to use to run this file. And how does he know that? From a simple file association.

"But the shell does not use CreateProcess when I double click on the file (or bat )? Why does it work with me?"

No. The shell uses the ShellExec API, which before running CreateProcess scans the registry to identify how to "execute" the file, or which program to call to handle the file, and then mount the appropriate command line. >     

29.03.2015 / 22:16