Newsgroups : Borland : borland.public.delphi.rtl.win32 : 2007 Aug : CreateProcess / Application not started to the foreground

www.cryer.info
Managed Newsgroup Archive

CreateProcess / Application not started to the foreground

Subject:CreateProcess / Application not started to the foreground
Posted by:"Adrien Reboisson" (nospam@nospam.com)
Date:Thu, 9 Aug 2007 09:49:14

Hi,

I'm trying to figure out WHY sometimes when I CreateProcess an
application, it's main window is not shown on foreground, but behind the
current maximized window.

Okay, I think it's related to the more complex way I use CreateProcess
here - but anyway, I don't understand why sometimes it works and
sometimes it does not work.

Say I've 3 applications :
- The first one is launched maximized ("application 1").
- The second one is launched without any GUI ("application 2"). It's a
kind of "proxy application", which receives requests from "application
1" through a named pipe. A typical request contains the name of the app
to run, the parameters and the local user which have to be impersonated,
if any. This application runs elevated and use
CreateProcess/CreateProcessWithLogonW according to the kind of the
request it receives.
- The third one is the application to run ("application 3"). Not much to
say about it. A regular Delphi Win 32 application.

So we have the following calling chain :

"Application 1" -- named pipe --> "Application 2" --
CreateProcess/CreateProcessWithLogonW --> " Application 3"

The first time "application 1" runs "application 3" through "application
2", all works just fine. Before executing various actions, a modal
dialog is displayed by App 2, and this dialog is displayed in front of
the maximized window belonging to App 1. Fine. Perfect.

But, the other times (why ?), the dialog shown by "application 2" is
displayed BEHIND "application 1". So, in short, the guy behind the
screen gets puzzled since he clicked on a button, and nothing happens.
He has to minimize the application to find the modal dialog in order to
validate it. Of course, the average user will never do that and will
just send to me a bug report : "hey, your application does nothing !"

So, do have you ever experienced this kind of problem ? I currently use
Delphi 2007 - I think the bug wasn't present with D7... I tried to use
MainFormOnTaskBar := True without any result. The hidden dialog is
displayed modaly, before calling Application.Run() in "application 3",
it may be linked with the way Delphi processes messages ? Anyway, it's
the same behaviour on XP and Vista.

There is the code I use to run the process in "application 2" :

function SetWinPos(Handle: HWND; LParam: Longint): Bool; stdcall;
begin
    Result := SetWindowPos(Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE or
SWP_NOSIZE or
      SWP_NOACTIVATE or SWP_SHOWWINDOW);
end;

class function TThRequestWrapper.InternalCreateProcess(
   const AHandle: Cardinal;
   const AAppPath, AAppParameters, AUser, APassword: string;
   AEnableImpersonation: Boolean): Boolean;
var
   wUsername, wDomain, wPassword, wApp, wParameters: WideString;
   StartupInfo: TStartupInfo;
   ProcessInfo: TProcessInformation;
   LUser, LDomain: string;
   LSecurityAttributes: TSecurityAttributes;
   PSecurityDescriptor: PSECURITY_DESCRIPTOR;
begin
   PSecurityDescriptor := AllocMem(SECURITY_DESCRIPTOR_MIN_LENGTH);
   InitializeSecurityDescriptor(PSecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION);
   SetSecurityDescriptorDacl(PSecurityDescriptor, True, nil, False);
   LSecurityAttributes.nLength := SizeOf(LSecurityAttributes);
   LSecurityAttributes.lpSecurityDescriptor := PSecurityDescriptor;
   LSecurityAttributes.bInheritHandle := True;

   FillChar(StartupInfo, SizeOf(StartupInfo), 0);
   StartupInfo.cb := SizeOf(StartupInfo);
   StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
   StartupInfo.wShowWindow := SW_SHOW;

   try
     if not GetCurrentUserAndDomain(LUser, LDomain) then
       AEnableImpersonation := False;

     if (AEnableImpersonation) and (not ((SameText(LUser, AUser)))) then
     begin
       wUsername := AUser;
       wDomain := '.';
       wPassword := APassword;
       wApp := AAppPath;
       wParameters := AAppParameters;

       Result := CreateProcessWithLogonW(pwidechar(wUsername),
                                       pwidechar(wDomain),
                                       pwidechar(wPassword),
                                       LOGON_WITH_PROFILE,
                                       pwidechar(wApp),
                                       pwidechar(wParameters),
                                       CREATE_DEFAULT_ERROR_MODE,
                                       nil,
                                       nil,
                                       StartupInfo,
                                       ProcessInfo);

     end else
     begin
       Result := CreateProcess(PChar(AAppPath),
         PChar(AAppParameters),
         @LSecurityAttributes,
         nil,
         True,
         NORMAL_PRIORITY_CLASS,
         nil,
         nil,
         StartupInfo,
         ProcessInfo
         );
     end;

     if not Result then
       MessageBox(AHandle, PChar(Format(strCannotStartTask,
[SysErrorMessage(GetLastError())])), nil,
         MB_ICONERROR)
     else
     begin
       WaitForInputIdle(ProcessInfo.hProcess, 15000); { Wait
initialization }
       EnumThreadWindows(Processinfo.dwThreadid, @SetWinPos, 0); { Make
app foreground -- useful hack ??? }
       while WaitForSingleObject(ProcessInfo.hProcess, 500) =
WAIT_TIMEOUT do;
       CloseHandle(ProcessInfo.hProcess);
       CloseHandle(ProcessInfo.hThread);
     end;
   finally
     FreeMem(PSecurityDescriptor);
   end
end;

Any hint greatly appreciated.

Best regards,

A.R.

Replies:

www.cryer.info
Managed Newsgroup Archive