Creating bat at runtime and process in Delphi

Asked

Viewed 3,305 times

4

I have two functions that create a file bat and runs it, but I’m just not getting to create the process (CreateProcess returns False) and I can’t identify the error.

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

Note: The same function worked in XE5.

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

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:

**EDITION:**After the help of the colleagues she was 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;
  • Instead of simply returning -1, call the Raiselastoserror function

  • You are letting leak the process Handles and the thread you created as well, you should clean them: CloseHandle(ProcessInfo.hProcess);``CloseHandle(ProcessInfo.hThread);

  • Thanks for the tips!

1 answer

3


A file bat is not an executable. Like sh, it is just a text file, which needs to be interpreted and then yes 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 figure out which interpreter to use to run the program (this is the line function #!/bin/sh in the archives sh and in others).

Therefore, in Windows, it is necessary to invoke the interpreter in order for it to run the bat. On Linux, this program would be the bash (or equivalent). In Windows, it is the cmd.exe.

Thus, your command must execute the cmd and pass by parameter the bat to be executed. I modified its original function to do this. I didn’t test it, because I don’t have Delphi installed (nor Lazarus), but this is the concept. I also added the commands to close the created Handles, as comments on 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;

Don’t forget that you may need to add " in the arguments if they have spaces!

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

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

"But the shell doesn’t use CreateProcess when I double-click the file (or bat)? Why does it work and not with me?"

No. Shell uses API ShellExec, that before executing the CreateProcess scans the record to identify how to "run" the file, or what program to call to manipulate the file, and then mounts the appropriate command line.

  • 2

    +1 for the explanation. Thank you very much, when you arrive in a machine with Delphi I will test.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.