为了在程序实现下述目的:
1.打开一个计算器供用户使用;
2.但只打开一次,如果没有关闭,下次再用按钮打开计算器时,把上次打开的调到前面;
3.程序关闭时,同时关闭可能打开的计算器;
说白了,就是如何调用一个外部程序,同时获得这个程序窗口的句柄
从以前讨论中,抄得部分代码,"组装"成下面的样子:用CreateProcess
打开计算器,用EnumThreadWindows查找打开的计算器窗口句柄,
用ShowWindows显示计算器,用TerminateProcess
或者TerminateThread关闭可能已经打开的计算器.
但是EnumThreadWindows部分的代码被说成是画蛇添足,因为
CreateProcess中已经有了窗口句柄?或者说是线程句柄?那么如何
用这个线程句柄得到窗口句柄呢?因为ShowWindows要使用一个窗口
句柄?EnumWindows好象又没办法找到这个特定的计算器窗口?不用
CreateProcess,有其他API可以即打开外部程序,又同时获得这个程序
的窗口句柄的好办法吗?或者直接用GetTopWindow? 实在想不通...
还有,用EnumThreadWindows时,会产生一个延时?外面要加个While,
不然会打开五六个计算器后,才能找到计算器窗口? why?
最后,千万别说"...都不知道?!",因为我确实不知道,代码都是抄的.
unit...
interface
uses...
type
EnumThreadWndProc = function(hWnd:HWND; lParam:LPARAM): Boolean;
TfrmCreateAndRestore = class(TForm)
...
end;
function Enum(hWnd:HWND; lParam:LPARAM): Boolean;stdcall;
var
frmCreateAndRestore: TfrmCreateAndRestore;
CalledWinHandle: THandle;
ProcessInfo: TProcessInformation;
temp: THandle;
implementation
{$R *.DFM}
function Enum(hWnd:HWND; lParam:LPARAM): Boolean;
{回调函数}
begin
if GetTopWindow(hWnd) <> 0 then
CalledWinHandle := hWnd;
Result:=True;
end;
procedure TfrmCreateAndRestore.btnOpenCalcClick(Sender: TObject);
{打开计算器,同时获得窗口句柄}
var
StartInfo: TStartupInfo;
CallBackProc: EnumThreadWndProc;
ExitCode: Cardinal;
begin
if CalledWinHandle <> 0 then
begin
if GetExitCodeProcess(ProcessInfo.hProcess, ExitCode) then
begin
if ExitCode = 0 then
begin
ShowMessage('Calc have exited'); //测试用的
CalledWinHandle := 0;
end;
end
else begin
ShowMessage('Can''t retrive Calc window'); //测试用的
CalledWinHandle := 0;
end;
end;
if CalledWinHandle = 0 then
begin
//创建进程,打开计算器
FillChar(StartInfo, SizeOf(StartInfo), #0);
with StartInfo do
begin
cb := SizeOf(StartInfo);
dwFlags := StartF_UseShowWindow;
wShowWindow := SW_NORMAL;
end;
if CreateProcess(nil, PChar('Calc'), nil, nil, True,
CREATE_DEFAULT_ERROR_MODE, nil, nil, StartInfo, ProcessInfo) then
begin
//获得窗口句柄
CallBackProc := @Enum;
while CalledWinHandle = 0 do
//如果不做这个While,就会要打开五六个计算器才能找到,why?
EnumThreadWindows(ProcessInfo.dwThreadId, @CallBackProc, 0);
end
else begin
ShowMessage('Create fail'); //测试用的
Exit;
end;
end;
//显示计算器
if IsWindowVisible(CalledWinHandle) then
begin
SetForeGroundWindow(CalledWinHandle);
ShowWindow(CalledWinHandle, SW_RESTORE);
end
else
ShowWindow(CalledWinHandle, SW_SHOW);
end;
procedure TfrmCreateAndRestore.FormClose(Sender: TObject;
var Action: TCloseAction);
//窗口关闭时,同时关闭可能已经打开的计算器
var
ProcessHandle: THandle;
begin
if ProcessInfo.dwProcessId <> 0 then
begin
ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, False, ProcessInfo.dwProcessId);
if not TerminateProcess(ProcessHandle, 0) then
//或者直接用 TerminateThread(ProcessInfo.hThread, 0)也行
ShowMessage('Close Calc error'); //测试用的
end;
end;