• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 330
  • Last Modified:

ShellExecuteEx

hi Experts,

I start a windows application (let's say notepad) using ShellExecuteEx.

From here, I get hProcess.

Now, having that much, how can I make a call activate the application and bring it to front?

graga
0
graga
Asked:
graga
1 Solution
 
ginsonicCommented:
0
 
MadshiCommented:
The problem is: How do you know which main window belongs to the given hProcess? That's almost impossible to know, since for enumerating windows and that stuff you need the process *ID*, not the handle. And there is no documented way to get the process ID from the handle.

So you should forget about ShellExecuteEx and instead use CreateProcess. This way you get the process ID and can then call EnumWindows or EnumThreadWindows to find out the main window of the process. If you want to start a document rather than an executable, use FindExecutable prior to calling CreateProcess.

Regards, Madshi.
0
 
TasomiaCommented:
Hi,

Try this:

function WinExecAndWait32(FileName: string; Visibility: Integer): Integer;
var
  zAppName: array[0..512] of Char;
  zCurDir: array[0..255] of Char;
  WorkDir: string;
  StartupInfo: TStartupInfo;
  ProcessInfo: TProcessInformation;
  r: DWORD;
begin
  StrPCopy(zAppName, FileName);
  GetDir(0, WorkDir);
  StrPCopy(zCurDir, WorkDir);
  FillChar(StartupInfo, SizeOf(StartupInfo), #0);
  StartupInfo.cb          := SizeOf(StartupInfo);
  StartupInfo.dwFlags     := STARTF_USESHOWWINDOW;
  StartupInfo.wShowWindow := Visibility;
  if not CreateProcess(nil,
    zAppName, // pointer to command line string
    nil, // pointer to process security attributes
    nil, // pointer to thread security attributes
    False, // handle inheritance flag
    CREATE_NEW_CONSOLE or // creation flags
    NORMAL_PRIORITY_CLASS,
    nil, //pointer to new environment block
    nil, // pointer to current directory name
    StartupInfo, // pointer to STARTUPINFO
    ProcessInfo) // pointer to PROCESS_INF
    then Result := -1
  else
  begin
    r := WaitForInputIdle(ProcessInfo.hProcess, 1000);
    while r <> 0 do
    begin
      if r = $FFFFFFFF then RaiseLastWin32Error;
      r := WaitForInputIdle(ProcessInfo.hProcess, 1000);
      Sleep(50);
    end;
    Result := ProcessInfo.dwThreadId;
    CloseHandle(ProcessInfo.hProcess);
    CloseHandle(ProcessInfo.hThread);
  end;
end; { WinExecAndWait32 }

function EnumProc(aWnd: HWND; var wnd: HWND): BOOL; stdcall;
begin
  Result := True;
  if (GetWindowLong(aWnd, GWL_HWNDPARENT) = 0) and
    (IsWindowVisible(aWnd) or IsIconic(aWnd)) then
  begin
    Result := False;
    wnd := aWnd;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  threadID: DWORD;
  wnd: HWND;
  buf: array [0..255] of char;
begin
  threadID := WinExecAndWait32('notepad.exe', SW_SHOWNORMAL);
  if threadID = -1 then
  begin
    ShowMessage('Error....');
    Exit;
  end;
  Sleep(100);
  wnd := 0;
  EnumThreadWindows(threadID, @EnumProc, Integer(@wnd));
  memo1.Clear;
  memo1.Lines.Add(Format('Found window, handle: %d', [wnd]));
  GetClassname(wnd, buf, SizeOf(buf));
  memo1.Lines.Add(Format('Classname is %s', [buf]));
  SendMessage(wnd, WM_GETTEXT, SizeOf(buf), Integer(@buf));
  memo1.Lines.Add(Format('Caption is %s', [buf]));
end;
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
hashirviqasCommented:
It is really quite simple.

Try this

uses ShellApi;
...
ShellExecute(Handle, 'open',
  'c:\Windows\notepad.exe', nil, nil, SW_SHOWNORMAL);


If you wanted to open a file with notepad, then use this instead;

ShellExecute(Handle,'open',
  'c:\windows\notepad.exe','c:\mytext.txt',
  nil, SW_SHOWNORMAL);

As a matter of fact you can open up a site with the default web browser too

ShellExecute(Handle, 'open',
  'http://www.dawn.com',nil,nil, SW_SHOWNORMAL);


or how about if you want to send an email message with default mail client on your win 32 box;

var em_subject, em_body, em_mail : string;
begin
 em_subject := 'This is my subject line';
 em_body := 'my Message body text goes here';

 em_mail := 'mailto:me@me.com?subject=' +
   em_subject + '&body=' + em_body ;

 ShellExecute(Handle,'open',
   PChar(em_mail), nil, nil, SW_SHOWNORMAL);
end;

Let me know if you have other questions... Hope these examples help



0
 
gragaAuthor Commented:
Hi Experts,

I'm just going now through your suggestions. I'll explain the scenario further:

I have a small menu system that can execute a number of different programs, both DOS and Windows.

When I select a program from the menu, this program is started.

When I select a program that has already been started, I want to find the program and bring it to front, rather than starting a new instance of the program.

To maintain a list of programs I have started, I keep a list of process ID's in a simple TList holding:

ProcessList: TList;

PProcess: ^AProcess
AProcess = record
           MenuOption: string;
           ProcessID: DWORD
           end;

Now, when a menu item is selected, I loop through my ProcessList looking for MenuOption selected.
When it is not there, I start the program.
If found, I check if the process is still running.
If running, I want to bring it to front, otherwise I remove entry from list, start the process and add the process to the list again.

So, my question summarises what I want to do:
- Start application
- Get some information from started application that I can use to activate it
- Activate application using the above information.

I hope this clarifies the problem.

I will raise points for working example.

graga
0
 
pnh73Commented:
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Accept answer from ginsonic

Please leave any comments here within the next seven days.
 
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
 
Paul (pnh73)
EE Cleanup Volunteer
0
 
pnh73Commented:
Thankyou for your response

Paul (pnh73)
EE Cleanup Volunteer
0

Featured Post

[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now