Delphi Create a Process or Shelling to start up an external application.

logo

Delphi Create a Process or Shelling to start up an external application.

Since Windows 10 has been released there has been hiccups when dealing with the Windows API. The strange behavior may not return an error code and may actually end up doing nothing leaving you more perplexed then ever.
For Delphi developers the best thing to do is retire the ShellExecute API call and convert it over to ShellExecuteEX or to create a separate process you should use CreateProcess.

Let’s examine the simple task of calling


ShellExecute(0, 'open', Pchar('DocumentName.pdf'), '', '', SW_SHOWNORMAL);

work under Windows 7 and 8, which would start the Acrobat Reader and open the file but under Windows 10 this no longer is the case. So the next step was to update the call to use ShellExecuteEX instead.


ShellInfo := Default(TShellExecuteInfo);
ShellInfo.cbSize := SizeOf(TShellExecuteInfo);
ShellInfo.lpFile := PChar(Current_Client_Documents + FileName +'.pdf');
ShellInfo.nShow := SW_SHOWNORMAL;

try
ShellExecuteEx(@ShellInfo);

The actual code will prepare the Object ShellInfo to contain all of the necessary data to start up the Acrobat Reader and display the generated PDF.

In the case of Createprocess API call the following code does the trick but realize the problem of this call, passing in a parameter will not work. Most likely you will not see anything. There are numerous


procedure ExecProcess(ProgramName : String; Wait: Boolean);
var
StartupInfo : TStartupInfo;
ProcessInfo : TProcessInformation;
ProcessCreated : Boolean;

begin
{ fill with known state }
FillChar(StartupInfo,SizeOf(TStartupInfo),#0);
FillChar(ProcessInfo,SizeOf(TProcessInformation),#0);
StartupInfo.cb := SizeOf(TStartupInfo);

ProcessCreated := CreateProcess(nil, PChar(ProgramName), nil, nil,False,
CREATE_NEW_PROCESS_GROUP+NORMAL_PRIORITY_CLASS,
nil, nil, StartupInfo, ProcessInfo);
{ Check whether to wait }
if ProcessCreated then
begin
if Wait then
WaitForSingleObject(ProcessInfo.hProcess, INFINITE)
else
ShowMessage(Error: The ‘+ProgramName+’ could not execute!’);
end;

CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);
end;

 Wrap-up

The Windows API indicates that the first line should be the Application that you wish to start and the second parameter should be any arguments you wish to send to the application. On Windows 10 this is something that was not working correctly.

BOOL WINAPI CreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);

This does work and you can modify it to whatever you need it to do.  It is Ok for you to use ShellExecuteEX and simply using what has been demonstrated above.