Why does CreateProcess give error 193 (%1 is not a valid Win32 app)
Asked Answered
C

2

35

The code below fails to start documents. I get error 193 (%1 is not a valid Win32 app). Starting executables work fine. The files are properly associated, they start the corresponding app when double clicked. I have searched SO and elsewhere for the error message, createprocess stuff etc. (E.g. Why is CreateProcess failing in Windows Server 2003 64-bit? I know about quoting the command line.

  • This is a Delphi XE2 (Update 4) Win32 app in a Win7 64bit VMWare VM.

  • The code also fails on the host machine (Win7 64 bit) and in a Virtual PC VM with 32bit XP.

  • The apps that should start in the Win7 VM (Excel 2003 and Crimson Editor) are 32 bit.

  • The failure occurs both when starting from the IDE or when running the test app standalone

  • It used to be Delphi2007 code, the compiled D2007 app where this code comes from works fine everywhere.

What's wrong with the code?

procedure StartProcess(WorkDir, Filename: string; Arguments : string = '');
var
  StartupInfo  : TStartupInfo;
  ProcessInfo  : TProcessInformation;
  lCmd         : string;
  lOK          : Boolean;
  LastErrorCode: Integer;
begin
  FillChar( StartupInfo, SizeOf( TStartupInfo ), 0 );
  StartupInfo.cb := SizeOf( TStartupInfo );
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  StartupInfo.wShowWindow := sw_Normal;

  FillChar( ProcessInfo, SizeOf( TProcessInformation ), 0 );

  lCmd := '"' +  WorkDir + FileName + '"';     // Quotes are needed https://mcmap.net/q/450263/-paths-and-createprocess
  if Arguments <> '' then lCmd := lCmd + ' ' + Arguments;

  lOk := CreateProcess(nil,
                       PChar(lCmd),
                       nil,
                       nil,
                       FALSE,  // TRUE makes no difference
                       0,      // e.g. CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS makes no difference
                       nil,
                       nil,    // PChar(WorkDir) makes no difference
                       StartupInfo,
                       ProcessInfo);

  if lOk then
  begin
    try
      WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
    finally
      CloseHandle( ProcessInfo.hThread );
      CloseHandle( ProcessInfo.hProcess );
    end;
  end
  else
  begin
    LastErrorCode := GetLastError;
    ShowMessage(IntToStr(LastErrorCode) + ': ' + SysErrorMessage(LastErrorCode));
  end;
end;

procedure TFrmStartProcess.Button1Click(Sender: TObject);
begin
   StartProcess('c:\program files (x86)\axe3\','axe.exe');    // Works
end;

procedure TFrmStartProcess.Button2Click(Sender: TObject);
begin
   StartProcess('d:\','klad.xls');                            // Fails
end;

procedure TFrmStartProcess.Button3Click(Sender: TObject);
begin
   StartProcess('d:\','smimime.txt');                         // Fails
end;
Cyrillic answered 28/9, 2012 at 9:23 Comment(5)
What happens for say the last one if you specifically call notepad on the text file?Begorra
I am not familiar with Delphi, but WINAPI CreateProcess() can be used to start .exes only. If want to run other types of files you need to use ShellExecute().Rodrickrodrigez
@hjmd That code used to work in the previous code version, calling .XLS files.Cyrillic
What is the difference between the previous code version and this version? Were you starting cmd with a parameter to open the .xls? Post the smallest reproducible sample that works in Delphi 2007 and fails in Delphi XE2.Buchenwald
See my comment below David's anser - the old code actually did not start other types of files.Cyrillic
J
41

The most likely explanations for that error are:

  1. The file you are attempting to load is not an executable file. CreateProcess requires you to provide an executable file. If you wish to be able to open any file with its associated application then you need ShellExecute rather than CreateProcess.
  2. There is a problem loading one of the dependencies of the executable, i.e. the DLLs that are linked to the executable. The most common reason for that is a mismatch between a 32 bit executable and a 64 bit DLL, or vice versa. To investigate, use Dependency Walker's profile mode to check exactly what is going wrong.

Reading down to the bottom of the code, I can see that the problem is number 1.

Jollification answered 28/9, 2012 at 9:34 Comment(2)
O my goodness. We are rewriting our code from D2007 to XE2 and in the process doing away with some external libraries. In that process we threw away a third party 'Launcher' component that used ShellExecute, and replaced it with our own 'Launcher' component that was only suited for executable and hence used CreateProcess. How confusing can it get. Sorry guys.Cyrillic
#2 bit me yesterday. Delphi adds both the 32 bit BPL and 64 bit BPL paths to the same global path, so the DLL names MUST differ, I learned yesterday, after some pain. This question is useful on its own. Keep it.Mongoloid
S
7

Your Button2Click and Button3Click functions pass klad.xls and smimime.txt. These files most likely aren't actual executables indeed.

In order to open arbitrary files using the application associated with them, use ShellExecute

Stoush answered 28/9, 2012 at 9:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.