skynergy
asked on
Get the handle of a windows application that was launched using ShellExecute
I want to get the handle of an windows application which was launched using ShellExecute so that later I can use the SetForegroundWindow to show it again instead of launching another instance. I dont want to use the GetWindowText api call to get the handle of that aplpication. I know there is an instance handle that gets returned but it isn't the same as the actual handle of the application. Just note I am talking about launching other windows appliactions which are not delphi apps i.e. like notepad for instance. So I want to launch notepad using ShellExecute get the handle for that instance of notepad, use SetForegroundWindow to show that instance of Notepad without searching the desktop windows for a title of 'notepad' to get the handle. How do I do this? Thanx in advance!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
When you use ShellExecute IF you using it with (sw_show)...
You could use GetForegroundWindow which will return a handle for the focused window.
You said :
>> I know there is an instance handle that gets returned but it isn't the same as the actual handle of the application.
This could happen for many reasons.
Maybe this is an ActiveX control..or
It's not mandatory in Windows that a process has to have a window ... or
As ZhaawZ said an application may have many windows.
You could use WindowFromPoint and use the mouse to get the handle of every window in the application.
You could use GetForegroundWindow which will return a handle for the focused window.
You said :
>> I know there is an instance handle that gets returned but it isn't the same as the actual handle of the application.
This could happen for many reasons.
Maybe this is an ActiveX control..or
It's not mandatory in Windows that a process has to have a window ... or
As ZhaawZ said an application may have many windows.
You could use WindowFromPoint and use the mouse to get the handle of every window in the application.
well CreateProcess launches the program returning the PID, not the window handle, then you enum all the windows then convert the window handle to a PID and then compare it to the PID which got returned by createprocess, when you find a match the handle must be that..
ASKER
Thank you for all the feedback guys. Give me some time to test your suggestions.
I have tried Pcsentinel's code but it doesn't bring the opened notepad to the front. Am I missing something?
I have tried Pcsentinel's code but it doesn't bring the opened notepad to the front. Am I missing something?
I think the problem in this question is the class.
Asker is saying that he doesnt want to use FindWindow because he doesnt get the classname right.
The problem is that you are going to get the same class name you got with FindWindow what ever you try...
Maybe this is an ActiveX menu..
Please try this application :
http://www.dennisbabkin.com/php/download.php?what=WinID
Asker is saying that he doesnt want to use FindWindow because he doesnt get the classname right.
The problem is that you are going to get the same class name you got with FindWindow what ever you try...
Maybe this is an ActiveX menu..
Please try this application :
http://www.dennisbabkin.com/php/download.php?what=WinID
unit ThreadtoWnd;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
WindowList: TList;
implementation
{$R *.DFM}
function GetWindow (Handle: HWND; LParam: longint): bool; stdcall;
begin
Result := true;
WindowList.Add (Pointer(Handle));
end;
Function GetHandles(ThreadID: Cardinal): Hwnd;
var i: integer;
wnd,Hnd: HWND;
Buffer: array [0..255] of char;
ProcessID,CPid: DWord;
begin
Result:=0;
WindowList := TList.Create;
EnumWindows(@GetWindow,Wnd );
for i := 0 to WindowList.Count - 1 do
begin
Hnd := HWND (WindowList [i]);
GetWindowText (Hnd, Buffer, SizeOf (Buffer) - 1);
getclassname(hnd,buffer,si zeof(buffe r));
GetWindowThreadProcessID(h nd,@cpid);
If ThreadID=CPID Then
Begin
Result:=Hnd;
Form1.Memo1.Lines.Add('Han dle '+IntToStr(Hnd)+' Text: '+Buffer+' TH '+IntToStr(ProcessID));
Exit;
End;
end;
End;
Function ExecApplication(APPName, CmdLine: String): HWnd;
var
StartInfo: TStartupInfo; ProcInfo: TProcessInformation;
begin
FillChar(StartInfo, SizeOf(StartInfo), 0);
StartInfo.cb:=SizeOf(Start Info);
StartInfo.dwFlags:=STARTF_ USESHOWWIN DOW;
StartInfo.wShowWindow:=SW_ Show;
if AppName<>'' then
CreateProcess(PChar(APPNam e), PChar(CmdLine), nil, nil, False, 0, nil, nil, StartInfo, ProcInfo);
Sleep(2000); //give notepad time to run (2 seconds)
Result:=GetHandles(ProcInf o.dwProces sId);
CloseHandle(ProcInfo.hProc ess);
CloseHandle(ProcInfo.hThre ad );
End;
procedure TForm1.Button1Click(Sender : TObject);
Var
Wnd: Hwnd;
N: Integer;
begin
Wnd:=ExecApplication('c:\w innt\notep ad.exe','' );
If Wnd<>0 Then
Begin
Sleep(3000); //pause for 3 seconds while you move notepad to the back
SetWindowPos(Wnd,HWND_TOPM OST,0,0,0, 0,SWP_NOMO VE Or SWP_NOSIZE);
End;
end;
end.
The only modification made is to bring it to the front using SetWindowPos, this should do exatly as you requested now.
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
WindowList: TList;
implementation
{$R *.DFM}
function GetWindow (Handle: HWND; LParam: longint): bool; stdcall;
begin
Result := true;
WindowList.Add (Pointer(Handle));
end;
Function GetHandles(ThreadID: Cardinal): Hwnd;
var i: integer;
wnd,Hnd: HWND;
Buffer: array [0..255] of char;
ProcessID,CPid: DWord;
begin
Result:=0;
WindowList := TList.Create;
EnumWindows(@GetWindow,Wnd
for i := 0 to WindowList.Count - 1 do
begin
Hnd := HWND (WindowList [i]);
GetWindowText (Hnd, Buffer, SizeOf (Buffer) - 1);
getclassname(hnd,buffer,si
GetWindowThreadProcessID(h
If ThreadID=CPID Then
Begin
Result:=Hnd;
Form1.Memo1.Lines.Add('Han
Exit;
End;
end;
End;
Function ExecApplication(APPName, CmdLine: String): HWnd;
var
StartInfo: TStartupInfo; ProcInfo: TProcessInformation;
begin
FillChar(StartInfo, SizeOf(StartInfo), 0);
StartInfo.cb:=SizeOf(Start
StartInfo.dwFlags:=STARTF_
StartInfo.wShowWindow:=SW_
if AppName<>'' then
CreateProcess(PChar(APPNam
Sleep(2000); //give notepad time to run (2 seconds)
Result:=GetHandles(ProcInf
CloseHandle(ProcInfo.hProc
CloseHandle(ProcInfo.hThre
End;
procedure TForm1.Button1Click(Sender
Var
Wnd: Hwnd;
N: Integer;
begin
Wnd:=ExecApplication('c:\w
If Wnd<>0 Then
Begin
Sleep(3000); //pause for 3 seconds while you move notepad to the back
SetWindowPos(Wnd,HWND_TOPM
End;
end;
end.
The only modification made is to bring it to the front using SetWindowPos, this should do exatly as you requested now.
Sorry , the showwindow will bring the window back from a minimised state,
add BringWindowToFront as in
ShowWindow(GetMainAppWndFr omPid(fPID ),SW_SHOW) ;
BringWindowToTop(GetMainAp pWndFromPi d(fPID));
regards
add BringWindowToFront as in
ShowWindow(GetMainAppWndFr
BringWindowToTop(GetMainAp
regards
ASKER
Great! Both (pcsentinel & tobjectpascal) examples works very well and thank you for the help so far. To CodedK & ZhaawZ in my question I referred to the Notepad application as both a window and application, maybe not the same thing as a application can have more than one window but in the case of the notepad it is. Sorry if my windows api knowledge is a bit limited so I apologize if I dont use the correct terminology. I do know how to get the handle on a window by searching for its title text. My question was more directed to get the handle of the window when I launch it so that I dont have to go and search for the title of that window. I also dont want the user of the application to specify the title of the window, it was an option but I would prefer not to. Also I dont really want to use GetForegroundWindow to get the handle of the window when I used ShellExecute with swShow because I might be launching two or more different windows in succession which would make this difficult. I do appreciate the link for WinID thank you!
Just another question. If Notepad was launched and then minimised, how can I show it using the two examples and make the foreground window. I tried:
ShowWindow(hwnd, SW_SHOWDEFAULT);
BringWindowToTop(hwnd);
but this will show it but not select it.
Thank you!
Just another question. If Notepad was launched and then minimised, how can I show it using the two examples and make the foreground window. I tried:
ShowWindow(hwnd, SW_SHOWDEFAULT);
BringWindowToTop(hwnd);
but this will show it but not select it.
Thank you!
for restoring minimised window:
if GetWindowLong(hwnd, gwl_style) and ws_iconic <> 0 then ShowWindow(hwnd, sw_restore);
if GetWindowLong(hwnd, gwl_style) and ws_iconic <> 0 then ShowWindow(hwnd, sw_restore);
ASKER
Thanx this still restores the window but doesn't give it focus.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ZhaawZ, the code above combined with my previous code works fine
ASKER
Thank you for all the help guys, I really appreciate it!
GetWindowText() has nothing to do with getting handle ;] at least it *should not* have...