i use to create a custom function like winexec(...):Hwnd that will retun the handle of executed application.
i did use the findwindow() but having problem if it change w
There is no general way to get "the" window handle of an application because there's no guarantee that any program has one window handle. A program may have many top-level handles (i.e., Microsoft Word, one for each document), or it may have no windows at all. You might question what you really need the window handle for; there could be better ways of doing whatever it is you're trying to do that don't require any specific window handle.
WinExec
(which has been deprecated for nearly 15 years, so you should seriously consider not using it anymore) and ShellExecute
return absolutely no information about the programs they start, if indeed they start any program at all. (ShellExecute
might use DDE to send a command to an already-running instance of the application.) And if they start an application, it might finish running before your program gets to run anymore.
You can use CreateProcess or ShellExecuteEx instead. If they start a program, they will give you a process handle representing the program they started. You can use that to help you get additional information about the program, such as a list of its windows. Don't bother with FindWindow
; the caption and window class aren't guaranteed to be unique; a program might use the same class name for many different windows, and multiple instances of a program would use the same class name without much way to select the one you really want.
EnumWindows
is a function you can use to get a list of candidate window handles. You give it a function pointer, and it will call that function once for each top-level window on the desktop. You'll need a way of telling it which process you're interested in, and a way for it to return a list of results. The function only accepts one parameter, so the parameter will have to be a pointer to a structure that holds more information:
type
PWindowSearch = ^TWindowSearch;
TWindowSearch = record
TargetProcessID: DWord;
ResultList: TWndList;
end;
TWndList
is a type I made up to hold a list of HWnd
values. If you have Delphi 2009 or later, you could use TList<HWnd>
; for earlier versions, you could use a TList
descendant or whatever else you choose.
CreateProcess
will tell you the new process ID in the dwProcessID
member of the TProcessInformation
record it fills; ShellExecuteEx
only returns a process handle, so use GetProcessID on that. The window-enumerating function needs a callback function matching this signature:
function SelectWindowByProcessID(Wnd: HWnd; Param: LParam): Bool; stdcall;
You can use EnumWindows
to get a handle list like this:
function GetWindowListByProcessID(pid: DWord): TWndList;
var
SearchRec: TWindowSearch;
begin
Result := TWndList.Create;
try
SearchRec.TargetProcessID := pid;
SearchRec.ResultList := Result;
Win32Check(EnumWindows(SelectWindowByProcessID, LParam(@SearchRec)));
except
Result.Free;
raise;
end;
end;
You'll implement the callback function like this:
function SelectWindowByProcessID(Wnd: HWnd; Param: LParam): Bool; stdcall;
var
SearchRec: PWindowSearch;
WindowPid: DWord;
begin
SearchRec := PWindowSearch(Param);
Assert(Assigned(SearchRec));
GetWindowThreadProcessID(Wnd, WindowPid);
if WindowPid = SearchRec.TargetProcessID then
SearchRec.ResultList.Add(Wnd);
Result := True;
end;
Once you have the list, you can inspect other attributes of the window to determine which ones are really the ones you want. You might determine it by window title or class name, or perhaps by the other controls that are one that window.
When you're finished using the process handle, make sure you call CloseHandle
on it so the OS can clean up the process's bookkeeping information.
Try example 6 from this page (http://delphidabbler.com/tips/134) and just modify it a little bit. That's what I did.
if you want to split where you check and where you review your result you can do something like
var
//...
runNext : Boolean;
//...
begin
{ startup code from other sample here }
// but instead of if
runNext := ShellExecuteEx(@SEInfo);
{ some more code here }
// need delay before running next process
// run loop until window with Handle is closed
if runNext then
with SEInfo do
repeat
GetExitCodeProcess(SEInfo.hProcess, ExitCode);
Sleep(20);
Application.ProcessMessages;
CheckSynchronize();
until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
{ next process code here }
end;
I realize some of you will drop hate mail on this for throwing in Sleep(), but I'd rather not lock windows up until that execute is finished when I'm processing a boatload of stuff and waiting.
There is function named EnumWindows. I think it will be useful to you.
Check the following links for more information
http://delphi.about.com/od/windowsshellapi/l/aa080304a.htm
http://www.swissdelphicenter.ch/torry/showcode.php?id=327